updating HR and integrate it to modules
This commit is contained in:
parent
f62878214d
commit
6933c13c3e
@ -36,12 +36,12 @@ if ($method === 'GET') {
|
||||
a.id, a.start_time as start, a.end_time as end, a.reason, a.status,
|
||||
a.patient_id, a.doctor_id, a.nurse_id, a.visit_type, a.address,
|
||||
p.name as patient_name,
|
||||
d.name_$lang as doctor_name,
|
||||
n.name_$lang as nurse_name
|
||||
doc.name_$lang as doctor_name,
|
||||
nur.name_$lang as nurse_name
|
||||
FROM appointments a
|
||||
JOIN patients p ON a.patient_id = p.id
|
||||
LEFT JOIN doctors d ON a.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON a.nurse_id = n.id
|
||||
LEFT JOIN employees doc ON a.doctor_id = doc.id
|
||||
LEFT JOIN employees nur ON a.nurse_id = nur.id
|
||||
WHERE 1=1";
|
||||
|
||||
$params = [];
|
||||
@ -148,19 +148,27 @@ if ($method === 'GET') {
|
||||
];
|
||||
}
|
||||
|
||||
// Fetch Doctor Holidays
|
||||
$docHolidayQuery = "SELECT dh.*, d.name_$lang as doctor_name FROM doctor_holidays dh JOIN doctors d ON dh.doctor_id = d.id WHERE 1=1";
|
||||
// Fetch Doctor Holidays (from Leave Requests)
|
||||
// Updated to join employees instead of doctors
|
||||
$docHolidayQuery = "
|
||||
SELECT lr.id, lr.start_date, lr.end_date, lr.reason as note,
|
||||
lr.employee_id as doctor_id,
|
||||
e.name_$lang as doctor_name
|
||||
FROM leave_requests lr
|
||||
JOIN employees e ON lr.employee_id = e.id
|
||||
WHERE lr.status = 'Approved'";
|
||||
|
||||
$docHolidayParams = [];
|
||||
|
||||
// Date filtering for doctor holidays (ranges)
|
||||
if ($startStr && $endStr) {
|
||||
$docHolidayQuery .= " AND dh.start_date <= ? AND dh.end_date >= ?";
|
||||
$docHolidayQuery .= " AND lr.start_date <= ? AND lr.end_date >= ?";
|
||||
$docHolidayParams[] = date('Y-m-d', strtotime($endStr));
|
||||
$docHolidayParams[] = date('Y-m-d', strtotime($startStr));
|
||||
}
|
||||
|
||||
if ($doctor_id) {
|
||||
$docHolidayQuery .= " AND dh.doctor_id = ?";
|
||||
$docHolidayQuery .= " AND lr.employee_id = ?";
|
||||
$docHolidayParams[] = $doctor_id;
|
||||
}
|
||||
|
||||
@ -223,36 +231,16 @@ if ($method === 'GET') {
|
||||
];
|
||||
}
|
||||
|
||||
// Fetch Doctor Business Hours
|
||||
if ($doctor_id) {
|
||||
$scheduleStmt = $db->prepare("SELECT day_of_week as day, start_time as start, end_time as end FROM doctor_schedules WHERE doctor_id = ?");
|
||||
$scheduleStmt->execute([$doctor_id]);
|
||||
$schedules = $scheduleStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$bhMap = [];
|
||||
foreach ($schedules as $s) {
|
||||
$key = $s['start'] . '-' . $s['end'];
|
||||
if (!isset($bhMap[$key])) {
|
||||
$bhMap[$key] = [
|
||||
'daysOfWeek' => [],
|
||||
'startTime' => $s['start'],
|
||||
'endTime' => $s['end']
|
||||
];
|
||||
}
|
||||
$bhMap[$key]['daysOfWeek'][] = (int)$s['day'];
|
||||
}
|
||||
$businessHours = array_values($bhMap);
|
||||
} else {
|
||||
$st = $s['working_hours_start'] ?? '08:00';
|
||||
$et = $s['working_hours_end'] ?? '17:00';
|
||||
$businessHours = [
|
||||
[
|
||||
'daysOfWeek' => [0, 1, 2, 3, 4, 5, 6],
|
||||
'startTime' => $st,
|
||||
'endTime' => $et
|
||||
]
|
||||
];
|
||||
}
|
||||
// Set Business Hours (Global Default since individual schedules are removed)
|
||||
$st = $s['working_hours_start'] ?? '08:00';
|
||||
$et = $s['working_hours_end'] ?? '17:00';
|
||||
$businessHours = [
|
||||
[
|
||||
'daysOfWeek' => [0, 1, 2, 3, 4, 5, 6],
|
||||
'startTime' => $st,
|
||||
'endTime' => $et
|
||||
]
|
||||
];
|
||||
|
||||
echo json_encode([
|
||||
'events' => $events,
|
||||
@ -269,7 +257,8 @@ function checkDoctorHoliday($db, $doctor_id, $start_time) {
|
||||
if (!$doctor_id || !$start_time) return false;
|
||||
$date = date('Y-m-d', strtotime($start_time));
|
||||
try {
|
||||
$stmt = $db->prepare("SELECT COUNT(*) FROM doctor_holidays WHERE doctor_id = ? AND ? BETWEEN start_date AND end_date");
|
||||
// Query leave_requests directly using employee_id (which is $doctor_id)
|
||||
$stmt = $db->prepare("SELECT COUNT(*) FROM leave_requests WHERE employee_id = ? AND status = 'Approved' AND ? BETWEEN start_date AND end_date");
|
||||
$stmt->execute([$doctor_id, $date]);
|
||||
return $stmt->fetchColumn() > 0;
|
||||
} catch (PDOException $e) {
|
||||
|
||||
@ -2,52 +2,31 @@
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/../helpers.php';
|
||||
|
||||
// Prevent caching
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: 0');
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$db = db();
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$input = json_decode(file_get_contents('php://input'), true) ?? $_POST;
|
||||
$doctor_id = $_GET['doctor_id'] ?? null;
|
||||
|
||||
if ($method === 'GET') {
|
||||
$doctor_id = $_GET['doctor_id'] ?? null;
|
||||
if (!$doctor_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'Missing doctor_id']);
|
||||
exit;
|
||||
}
|
||||
if (!$doctor_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'Missing doctor_id']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("SELECT * FROM doctor_holidays WHERE doctor_id = ? ORDER BY start_date DESC");
|
||||
try {
|
||||
// $doctor_id is expected to be employee_id now
|
||||
$stmt = $db->prepare("
|
||||
SELECT start_date, end_date, reason
|
||||
FROM leave_requests
|
||||
WHERE employee_id = ? AND status = 'Approved' AND end_date >= CURDATE()
|
||||
");
|
||||
$stmt->execute([$doctor_id]);
|
||||
$holidays = $stmt->fetchAll();
|
||||
$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode(['success' => true, 'holidays' => $holidays]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($method === 'POST') {
|
||||
$action = $input['action'] ?? '';
|
||||
|
||||
if ($action === 'create') {
|
||||
$doctor_id = $input['doctor_id'] ?? null;
|
||||
$start_date = $input['start_date'] ?? null;
|
||||
$end_date = $input['end_date'] ?? null;
|
||||
$note = $input['note'] ?? '';
|
||||
|
||||
if ($doctor_id && $start_date && $end_date) {
|
||||
$stmt = $db->prepare("INSERT INTO doctor_holidays (doctor_id, start_date, end_date, note) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$doctor_id, $start_date, $end_date, $note]);
|
||||
echo json_encode(['success' => true]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'error' => 'Missing fields']);
|
||||
}
|
||||
} elseif ($action === 'delete') {
|
||||
$id = $input['id'] ?? null;
|
||||
if ($id) {
|
||||
$stmt = $db->prepare("DELETE FROM doctor_holidays WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
echo json_encode(['success' => true]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'error' => 'Missing ID']);
|
||||
}
|
||||
}
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'error' => 'DB Error: ' . $e->getMessage()]);
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ try {
|
||||
FROM patient_queue q
|
||||
JOIN patients p ON q.patient_id = p.id
|
||||
JOIN departments dept ON q.department_id = dept.id
|
||||
LEFT JOIN doctors d ON q.doctor_id = d.id
|
||||
LEFT JOIN employees d ON q.doctor_id = d.id
|
||||
$where
|
||||
ORDER BY
|
||||
CASE WHEN q.status = 'serving' THEN 1 WHEN q.status = 'waiting' THEN 2 ELSE 3 END,
|
||||
|
||||
2
db/migrations/20260322_add_employee_to_nurses.sql
Normal file
2
db/migrations/20260322_add_employee_to_nurses.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE nurses ADD COLUMN IF NOT EXISTS employee_id INT;
|
||||
ALTER TABLE nurses ADD CONSTRAINT fk_nurse_employee FOREIGN KEY (employee_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
59
db/migrations/20260322_merge_doctors_nurses_into_hr.sql
Normal file
59
db/migrations/20260322_merge_doctors_nurses_into_hr.sql
Normal file
@ -0,0 +1,59 @@
|
||||
-- Migration to merge Doctors and Nurses into HR (Employees)
|
||||
-- Step 1: Add new columns to hold Employee IDs
|
||||
ALTER TABLE visits ADD COLUMN IF NOT EXISTS doctor_employee_id INT NULL;
|
||||
ALTER TABLE appointments ADD COLUMN IF NOT EXISTS doctor_employee_id INT NULL;
|
||||
ALTER TABLE appointments ADD COLUMN IF NOT EXISTS nurse_employee_id INT NULL;
|
||||
|
||||
-- Step 2: Migrate data (if doctors/nurses have employee_id set)
|
||||
-- Update Visits
|
||||
UPDATE visits v
|
||||
JOIN doctors d ON v.doctor_id = d.id
|
||||
SET v.doctor_employee_id = d.employee_id
|
||||
WHERE d.employee_id IS NOT NULL;
|
||||
|
||||
-- Update Appointments (Doctor)
|
||||
UPDATE appointments a
|
||||
JOIN doctors d ON a.doctor_id = d.id
|
||||
SET a.doctor_employee_id = d.employee_id
|
||||
WHERE d.employee_id IS NOT NULL;
|
||||
|
||||
-- Update Appointments (Nurse)
|
||||
UPDATE appointments a
|
||||
JOIN nurses n ON a.nurse_id = n.id
|
||||
SET a.nurse_employee_id = n.employee_id
|
||||
WHERE n.employee_id IS NOT NULL;
|
||||
|
||||
-- Step 3: Drop old Foreign Keys (Constraint names might vary, so we try standard names or rely on DROP COLUMN to drop FKs in some DBs, but explicitly dropping FK is safer)
|
||||
-- Finding constraint names is hard in SQL script without dynamic SQL.
|
||||
-- However, in MariaDB/MySQL, dropping the column usually drops the FK.
|
||||
-- But to be safe, we will try to drop the standard named constraints if known, or just proceed with DROP COLUMN which should work if no other constraints block it.
|
||||
|
||||
ALTER TABLE visits DROP FOREIGN KEY IF EXISTS visits_ibfk_2; -- doctor_id
|
||||
ALTER TABLE appointments DROP FOREIGN KEY IF EXISTS appointments_ibfk_2; -- doctor_id
|
||||
ALTER TABLE appointments DROP FOREIGN KEY IF EXISTS appointments_ibfk_3; -- nurse_id
|
||||
|
||||
-- Also drop keys/indexes if they exist separate from FK
|
||||
ALTER TABLE visits DROP KEY IF EXISTS doctor_id;
|
||||
ALTER TABLE appointments DROP KEY IF EXISTS doctor_id;
|
||||
ALTER TABLE appointments DROP KEY IF EXISTS nurse_id;
|
||||
|
||||
-- Step 4: Drop old columns
|
||||
ALTER TABLE visits DROP COLUMN doctor_id;
|
||||
ALTER TABLE appointments DROP COLUMN doctor_id;
|
||||
ALTER TABLE appointments DROP COLUMN nurse_id;
|
||||
|
||||
-- Step 5: Rename new columns to match standard naming (or keep them and add FK)
|
||||
-- Let's rename them back to doctor_id and nurse_id but now they point to employees
|
||||
ALTER TABLE visits CHANGE COLUMN doctor_employee_id doctor_id INT NULL;
|
||||
ALTER TABLE appointments CHANGE COLUMN doctor_employee_id doctor_id INT NULL;
|
||||
ALTER TABLE appointments CHANGE COLUMN nurse_employee_id nurse_id INT NULL;
|
||||
|
||||
-- Step 6: Add new Foreign Keys to employees
|
||||
ALTER TABLE visits ADD CONSTRAINT fk_visit_doctor_employee FOREIGN KEY (doctor_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
ALTER TABLE appointments ADD CONSTRAINT fk_appt_doctor_employee FOREIGN KEY (doctor_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
ALTER TABLE appointments ADD CONSTRAINT fk_appt_nurse_employee FOREIGN KEY (nurse_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
|
||||
-- Step 7: Drop obsolete tables
|
||||
DROP TABLE IF EXISTS doctor_holidays; -- If exists
|
||||
DROP TABLE IF EXISTS doctors;
|
||||
DROP TABLE IF EXISTS nurses;
|
||||
@ -0,0 +1,25 @@
|
||||
-- Final cleanup for Doctors/Nurses migration
|
||||
|
||||
-- Fix Patient Queue Doctor ID (References doctors)
|
||||
ALTER TABLE patient_queue ADD COLUMN IF NOT EXISTS doctor_employee_id INT NULL;
|
||||
|
||||
-- Migrate data
|
||||
UPDATE patient_queue q
|
||||
JOIN doctors d ON q.doctor_id = d.id
|
||||
SET q.doctor_employee_id = d.employee_id
|
||||
WHERE d.employee_id IS NOT NULL;
|
||||
|
||||
-- Drop old FK
|
||||
ALTER TABLE patient_queue DROP FOREIGN KEY IF EXISTS patient_queue_ibfk_3;
|
||||
|
||||
-- Drop old column
|
||||
ALTER TABLE patient_queue DROP COLUMN doctor_id;
|
||||
|
||||
-- Rename new column
|
||||
ALTER TABLE patient_queue CHANGE COLUMN doctor_employee_id doctor_id INT NULL;
|
||||
|
||||
-- Add new FK to employees
|
||||
ALTER TABLE patient_queue ADD CONSTRAINT fk_queue_doctor_employee FOREIGN KEY (doctor_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
|
||||
-- Now drop doctors table
|
||||
DROP TABLE IF EXISTS doctors;
|
||||
56
db/migrations/20260322_merge_doctors_nurses_into_hr_fix.sql
Normal file
56
db/migrations/20260322_merge_doctors_nurses_into_hr_fix.sql
Normal file
@ -0,0 +1,56 @@
|
||||
-- Fix Migration: Merge Doctors and Nurses into HR (Employees) - Cleanup
|
||||
|
||||
-- 1. Drop dependent tables that reference doctors
|
||||
DROP TABLE IF EXISTS doctor_schedules;
|
||||
|
||||
-- 2. Fix Visits Nurse ID
|
||||
-- Add temp column if it doesn't exist (it wasn't added in previous migration)
|
||||
ALTER TABLE visits ADD COLUMN IF NOT EXISTS nurse_employee_id INT NULL;
|
||||
|
||||
-- Migrate data from nurses table to visits.nurse_employee_id
|
||||
UPDATE visits v
|
||||
JOIN nurses n ON v.nurse_id = n.id
|
||||
SET v.nurse_employee_id = n.employee_id
|
||||
WHERE n.employee_id IS NOT NULL;
|
||||
|
||||
-- Drop old FK on visits.nurse_id
|
||||
ALTER TABLE visits DROP FOREIGN KEY IF EXISTS fk_visit_nurse;
|
||||
|
||||
-- Drop old column visits.nurse_id
|
||||
-- We use a check to avoid error if it was already dropped (though unlikely)
|
||||
ALTER TABLE visits DROP COLUMN nurse_id;
|
||||
|
||||
-- Rename new column to nurse_id
|
||||
ALTER TABLE visits CHANGE COLUMN nurse_employee_id nurse_id INT NULL;
|
||||
|
||||
-- Add new FK to employees
|
||||
ALTER TABLE visits ADD CONSTRAINT fk_visit_nurse_employee FOREIGN KEY (nurse_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
-- 3. Fix Appointments Nurse ID
|
||||
-- Ensure nurse_employee_id exists (might have been created in previous migration)
|
||||
ALTER TABLE appointments ADD COLUMN IF NOT EXISTS nurse_employee_id INT NULL;
|
||||
|
||||
-- Migrate data again just in case
|
||||
UPDATE appointments a
|
||||
JOIN nurses n ON a.nurse_id = n.id
|
||||
SET a.nurse_employee_id = n.employee_id
|
||||
WHERE n.employee_id IS NOT NULL;
|
||||
|
||||
-- Drop old FK on appointments.nurse_id
|
||||
ALTER TABLE appointments DROP FOREIGN KEY IF EXISTS fk_appointment_nurse;
|
||||
|
||||
-- Drop old column appointments.nurse_id
|
||||
ALTER TABLE appointments DROP COLUMN nurse_id;
|
||||
|
||||
-- Rename new column to nurse_id
|
||||
ALTER TABLE appointments CHANGE COLUMN nurse_employee_id nurse_id INT NULL;
|
||||
|
||||
-- Add new FK to employees
|
||||
ALTER TABLE appointments ADD CONSTRAINT fk_appt_nurse_employee FOREIGN KEY (nurse_id) REFERENCES employees(id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
-- 4. Drop obsolete tables
|
||||
-- Now that FKs are gone, this should succeed.
|
||||
DROP TABLE IF EXISTS doctors;
|
||||
DROP TABLE IF EXISTS nurses;
|
||||
@ -1,4 +0,0 @@
|
||||
<?php
|
||||
require_once 'includes/layout/header.php';
|
||||
require_once 'includes/pages/doctor_holidays.php';
|
||||
require_once 'includes/layout/footer.php';
|
||||
25
doctors.php
25
doctors.php
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
$section = 'doctors';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$db = db();
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
|
||||
$is_ajax = isset($_GET['ajax_search']) || isset($_POST['ajax_search']);
|
||||
|
||||
if (!$is_ajax) {
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/includes/pages/doctors.php';
|
||||
|
||||
if (!$is_ajax) {
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
}
|
||||
@ -1 +1,32 @@
|
||||
<?php require_once 'includes/auth.php'; require_once 'includes/header.php'; require_once 'includes/pages/hr_attendance.php'; require_once 'includes/footer.php'; ?>
|
||||
<?php
|
||||
// Enable detailed error reporting for debugging
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$section = 'hr_attendance';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Try to connect to DB first
|
||||
try {
|
||||
$db = db();
|
||||
} catch (PDOException $e) {
|
||||
die("Database Connection Error: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
die("General Error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
|
||||
require_once __DIR__ . '/includes/pages/hr_attendance.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
@ -1,8 +1,32 @@
|
||||
<?php
|
||||
require_once 'includes/auth.php';
|
||||
require_once 'includes/header.php';
|
||||
// Enable detailed error reporting for debugging
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// Logic is in includes/pages/hr_dashboard.php
|
||||
require_once 'includes/pages/hr_dashboard.php';
|
||||
$section = 'hr_dashboard';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
require_once 'includes/footer.php';
|
||||
// Try to connect to DB first
|
||||
try {
|
||||
$db = db();
|
||||
} catch (PDOException $e) {
|
||||
die("Database Connection Error: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
die("General Error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
|
||||
require_once __DIR__ . '/includes/pages/hr_dashboard.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
@ -1 +1,32 @@
|
||||
<?php require_once 'includes/auth.php'; require_once 'includes/header.php'; require_once 'includes/pages/hr_leaves.php'; require_once 'includes/footer.php'; ?>
|
||||
<?php
|
||||
// Enable detailed error reporting for debugging
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$section = 'hr_leaves';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Try to connect to DB first
|
||||
try {
|
||||
$db = db();
|
||||
} catch (PDOException $e) {
|
||||
die("Database Connection Error: " . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
die("General Error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
|
||||
require_once __DIR__ . '/includes/pages/hr_leaves.php';
|
||||
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
@ -146,80 +146,6 @@ if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST')
|
||||
$_SESSION['flash_message'] = __('delete') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'add_doctor') {
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$tel = $_POST['tel'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$spec_en = $_POST['specialization_en'] ?? '';
|
||||
$spec_ar = $_POST['specialization_ar'] ?? '';
|
||||
$dept_id = $_POST['department_id'] ?: null;
|
||||
|
||||
if ($name_en && $name_ar) {
|
||||
$stmt = $db->prepare("INSERT INTO doctors (name_en, name_ar, tel, email, specialization_en, specialization_ar, department_id) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name_en, $name_ar, $tel, $email, $spec_en, $spec_ar, $dept_id]);
|
||||
$_SESSION['flash_message'] = __('add_doctor') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'edit_doctor') {
|
||||
$id = $_POST['id'] ?? '';
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$tel = $_POST['tel'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$spec_en = $_POST['specialization_en'] ?? '';
|
||||
$spec_ar = $_POST['specialization_ar'] ?? '';
|
||||
$dept_id = $_POST['department_id'] ?: null;
|
||||
|
||||
if ($id && $name_en && $name_ar) {
|
||||
$stmt = $db->prepare("UPDATE doctors SET name_en = ?, name_ar = ?, tel = ?, email = ?, specialization_en = ?, specialization_ar = ?, department_id = ? WHERE id = ?");
|
||||
$stmt->execute([$name_en, $name_ar, $tel, $email, $spec_en, $spec_ar, $dept_id, $id]);
|
||||
$_SESSION['flash_message'] = __('edit_doctor') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'delete_doctor') {
|
||||
$id = $_POST['id'] ?? '';
|
||||
if ($id) {
|
||||
$stmt = $db->prepare("DELETE FROM doctors WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$_SESSION['flash_message'] = __('delete') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'add_nurse') {
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$tel = $_POST['tel'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$dept_id = $_POST['department_id'] ?: null;
|
||||
|
||||
if ($name_en && $name_ar) {
|
||||
$stmt = $db->prepare("INSERT INTO nurses (name_en, name_ar, tel, email, department_id) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name_en, $name_ar, $tel, $email, $dept_id]);
|
||||
$_SESSION['flash_message'] = __('add_nurse') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'edit_nurse') {
|
||||
$id = $_POST['id'] ?? '';
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
$tel = $_POST['tel'] ?? '';
|
||||
$email = $_POST['email'] ?? '';
|
||||
$dept_id = $_POST['department_id'] ?: null;
|
||||
|
||||
if ($id && $name_en && $name_ar) {
|
||||
$stmt = $db->prepare("UPDATE nurses SET name_en = ?, name_ar = ?, tel = ?, email = ?, department_id = ? WHERE id = ?");
|
||||
$stmt->execute([$name_en, $name_ar, $tel, $email, $dept_id, $id]);
|
||||
$_SESSION['flash_message'] = __('edit_nurse') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'delete_nurse') {
|
||||
$id = $_POST['id'] ?? '';
|
||||
if ($id) {
|
||||
$stmt = $db->prepare("DELETE FROM nurses WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$_SESSION['flash_message'] = __('delete') . ' ' . __('successfully');
|
||||
$redirect = true;
|
||||
}
|
||||
} elseif ($_POST['action'] === 'add_department') {
|
||||
$name_en = $_POST['name_en'] ?? '';
|
||||
$name_ar = $_POST['name_ar'] ?? '';
|
||||
@ -322,7 +248,8 @@ if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST')
|
||||
|
||||
// Token Generation (Only for Doctor visits in Clinic usually)
|
||||
if (isset($_POST['generate_token']) && $_POST['generate_token'] == '1' && $doctor_id) {
|
||||
$stmtDoc = $db->prepare("SELECT department_id FROM doctors WHERE id = ?");
|
||||
// Updated to query employees table
|
||||
$stmtDoc = $db->prepare("SELECT department_id FROM employees WHERE id = ?");
|
||||
$stmtDoc->execute([$doctor_id]);
|
||||
$docData = $stmtDoc->fetch();
|
||||
$dept_id = $docData ? $docData['department_id'] : null;
|
||||
|
||||
@ -83,4 +83,8 @@ function require_permission($permission) {
|
||||
http_response_code(403);
|
||||
die("Access Denied: You do not have the required permission: " . htmlspecialchars($permission));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function is_admin() {
|
||||
return has_role('admin');
|
||||
}
|
||||
|
||||
@ -1,8 +1,20 @@
|
||||
<?php
|
||||
// Common data for selects
|
||||
$all_doctors = $db->query("SELECT id, name_$lang as name FROM doctors")->fetchAll();
|
||||
$all_patients = $db->query("SELECT id, name, phone, civil_id, dob, gender FROM patients")->fetchAll();
|
||||
$all_nurses = $db->query("SELECT id, name_$lang as name FROM nurses")->fetchAll();
|
||||
$all_doctors = $db->query("
|
||||
SELECT e.id, e.name_$lang as name
|
||||
FROM employees e
|
||||
JOIN positions p ON e.position_id = p.id
|
||||
WHERE UPPER(p.name_en) = 'DOCTOR'
|
||||
")->fetchAll();
|
||||
|
||||
$all_nurses = $db->query("
|
||||
SELECT e.id, e.name_$lang as name
|
||||
FROM employees e
|
||||
JOIN positions p ON e.position_id = p.id
|
||||
WHERE UPPER(p.name_en) = 'NURSE'
|
||||
")->fetchAll();
|
||||
|
||||
$all_patients = $db->query("SELECT id, name, phone, civil_id, dob, gender, address FROM patients")->fetchAll();
|
||||
$all_departments = $db->query("SELECT id, name_$lang as name FROM departments")->fetchAll();
|
||||
$all_employees = $db->query("SELECT id, name_$lang as name FROM employees")->fetchAll();
|
||||
$all_positions = $db->query("SELECT id, name_$lang as name FROM positions")->fetchAll();
|
||||
@ -19,12 +31,14 @@ $all_xrays = $db->query("SELECT id, name_$lang as name, price FROM xray_tests")-
|
||||
$all_drugs = $db->query("SELECT id, name_$lang as name, default_dosage, default_instructions, price FROM drugs")->fetchAll();
|
||||
|
||||
$scheduled_appointments = $db->query("
|
||||
SELECT a.id, p.name as patient_name, a.start_time, a.patient_id, a.doctor_id
|
||||
SELECT a.id, p.name as patient_name, a.start_time, a.patient_id, a.doctor_id,
|
||||
e.name_$lang as doctor_name
|
||||
FROM appointments a
|
||||
JOIN patients p ON a.patient_id = p.id
|
||||
LEFT JOIN employees e ON a.doctor_id = e.id
|
||||
WHERE a.status = 'Scheduled'
|
||||
ORDER BY a.start_time ASC")->fetchAll();
|
||||
|
||||
$all_countries = require __DIR__ . "/countries.php";
|
||||
|
||||
$all_cities = $db->query("SELECT id, name_$lang as name FROM cities")->fetchAll();
|
||||
$all_cities = $db->query("SELECT id, name_$lang as name FROM cities")->fetchAll();
|
||||
@ -327,6 +327,15 @@
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo __('linked_employee'); ?> (HR/Leaves)</label>
|
||||
<select name="employee_id" class="form-select select2-modal">
|
||||
<option value=""><?php echo __('none'); ?></option>
|
||||
<?php foreach ($all_employees as $emp): ?>
|
||||
<option value="<?php echo $emp['id']; ?>"><?php echo htmlspecialchars($emp['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
|
||||
@ -384,6 +393,15 @@
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo __('linked_employee'); ?> (HR/Leaves)</label>
|
||||
<select name="employee_id" id="edit_doctor_employee_id" class="form-select select2-modal">
|
||||
<option value=""><?php echo __('none'); ?></option>
|
||||
<?php foreach ($all_employees as $emp): ?>
|
||||
<option value="<?php echo $emp['id']; ?>"><?php echo htmlspecialchars($emp['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
|
||||
@ -1593,6 +1611,7 @@ function showEditDoctorModal(data) {
|
||||
document.getElementById('edit_doctor_spec_en').value = data.specialization_en || '';
|
||||
document.getElementById('edit_doctor_spec_ar').value = data.specialization_ar || '';
|
||||
document.getElementById('edit_doctor_dept_id').value = data.department_id || '';
|
||||
$('#edit_doctor_employee_id').val(data.employee_id).trigger('change');
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('editDoctorModal'));
|
||||
modal.show();
|
||||
@ -1752,4 +1771,3 @@ $(document).ready(function() {
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -217,12 +217,6 @@ $site_favicon = !empty($site_settings['company_favicon']) ? $site_settings['comp
|
||||
<?php if (has_permission('insurance')): ?>
|
||||
<a href="insurance.php" class="sidebar-link <?php echo $section === 'insurance' ? 'active' : ''; ?>"><i class="bi bi-shield-check me-2"></i> <?php echo __('insurance'); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (has_permission('doctors')): ?>
|
||||
<a href="doctors.php" class="sidebar-link <?php echo $section === 'doctors' ? 'active' : ''; ?>"><i class="bi bi-person-badge me-2"></i> <?php echo __('doctors'); ?></a>
|
||||
<a href="doctor_holidays.php" class="sidebar-link <?php echo $section === 'doctor_holidays' ? 'active' : ''; ?>"><i class="bi bi-calendar-x me-2"></i> <?php echo __('doctor_holidays'); ?></a>
|
||||
<a href="nurses.php" class="sidebar-link <?php echo $section === 'nurses' ? 'active' : ''; ?>"><i class="bi bi-person-heart me-2"></i> <?php echo __('nurses'); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (has_permission('reports')): ?>
|
||||
<a href="reports.php" class="sidebar-link <?php echo $section === 'reports' ? 'active' : ''; ?>"><i class="bi bi-bar-chart-line me-2"></i> <?php echo __('admin_reports'); ?></a>
|
||||
|
||||
@ -70,11 +70,11 @@ $total_labs = $db->query("SELECT COUNT(*) FROM laboratory_inquiries")->fetchColu
|
||||
|
||||
// Fetch Running Visits (Not Completed/Cancelled)
|
||||
$running_visits_sql = "
|
||||
SELECT v.*, p.name as patient_name, d.name_$lang as doctor_name, n.name_$lang as nurse_name
|
||||
SELECT v.*, p.name as patient_name, doc.name_$lang as doctor_name, nur.name_$lang as nurse_name
|
||||
FROM visits v
|
||||
JOIN patients p ON v.patient_id = p.id
|
||||
LEFT JOIN doctors d ON v.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON v.nurse_id = n.id
|
||||
LEFT JOIN employees doc ON v.doctor_id = doc.id
|
||||
LEFT JOIN employees nur ON v.nurse_id = nur.id
|
||||
WHERE v.status IN ('CheckIn', 'In Progress')
|
||||
ORDER BY v.visit_date ASC";
|
||||
$running_visits = $db->query($running_visits_sql)->fetchAll();
|
||||
@ -89,11 +89,11 @@ $patients = $db->query($patients_sql)->fetchAll();
|
||||
|
||||
// Today's Appointments
|
||||
$appointments_sql = "
|
||||
SELECT a.*, p.name as patient_name, d.name_$lang as doctor_name, n.name_$lang as nurse_name
|
||||
SELECT a.*, p.name as patient_name, doc.name_$lang as doctor_name, nur.name_$lang as nurse_name
|
||||
FROM appointments a
|
||||
JOIN patients p ON a.patient_id = p.id
|
||||
LEFT JOIN doctors d ON a.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON a.nurse_id = n.id
|
||||
LEFT JOIN employees doc ON a.doctor_id = doc.id
|
||||
LEFT JOIN employees nur ON a.nurse_id = nur.id
|
||||
WHERE DATE(a.start_time) = CURDATE()
|
||||
ORDER BY a.start_time ASC";
|
||||
$appointments = $db->query($appointments_sql)->fetchAll();
|
||||
|
||||
@ -1,179 +0,0 @@
|
||||
<?php
|
||||
$section = 'doctor_holidays';
|
||||
$db = db();
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
// Handle Form Submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
if ($action === 'create' || $action === 'update') {
|
||||
$doctor_id = $_POST['doctor_id'] ?? '';
|
||||
$start_date = $_POST['start_date'] ?? '';
|
||||
$end_date = $_POST['end_date'] ?? '';
|
||||
$note = $_POST['note'] ?? '';
|
||||
$id = $_POST['id'] ?? '';
|
||||
|
||||
if ($doctor_id && $start_date && $end_date) {
|
||||
if ($action === 'create') {
|
||||
$stmt = $db->prepare("INSERT INTO doctor_holidays (doctor_id, start_date, end_date, note) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$doctor_id, $start_date, $end_date, $note]);
|
||||
$_SESSION['flash_message'] = __('holiday_added_successfully');
|
||||
} else {
|
||||
$stmt = $db->prepare("UPDATE doctor_holidays SET doctor_id = ?, start_date = ?, end_date = ?, note = ? WHERE id = ?");
|
||||
$stmt->execute([$doctor_id, $start_date, $end_date, $note, $id]);
|
||||
$_SESSION['flash_message'] = __('holiday_updated_successfully');
|
||||
}
|
||||
}
|
||||
} elseif ($action === 'delete') {
|
||||
$id = $_POST['id'] ?? '';
|
||||
if ($id) {
|
||||
$stmt = $db->prepare("DELETE FROM doctor_holidays WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$_SESSION['flash_message'] = __('holiday_deleted_successfully');
|
||||
}
|
||||
}
|
||||
// Redirect to avoid resubmission
|
||||
echo "<script>window.location.href='doctor_holidays.php';</script>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch Doctors for dropdown
|
||||
$doctors = $db->query("SELECT id, name_$lang as name FROM doctors ORDER BY name_$lang ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch Holidays
|
||||
$holidays = $db->query("SELECT dh.*, d.name_$lang as doctor_name FROM doctor_holidays dh JOIN doctors d ON dh.doctor_id = d.id ORDER BY dh.start_date DESC")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h3 class="fw-bold text-secondary"><?php echo __('doctor_holidays'); ?></h3>
|
||||
<button class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#holidayModal" onclick="showCreateModal()">
|
||||
<i class="bi bi-plus-lg me-1"></i> <?php echo __('add_holiday'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo __('doctor'); ?></th>
|
||||
<th><?php echo __('start_date'); ?></th>
|
||||
<th><?php echo __('end_date'); ?></th>
|
||||
<th><?php echo __('note'); ?></th>
|
||||
<th class="text-end"><?php echo __('actions'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($holidays)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4 text-muted">
|
||||
<i class="bi bi-calendar-x display-6 d-block mb-2"></i>
|
||||
<?php echo __('no_holidays_found'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($holidays as $h): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($h['doctor_name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($h['start_date']); ?></td>
|
||||
<td><?php echo htmlspecialchars($h['end_date']); ?></td>
|
||||
<td><?php echo htmlspecialchars($h['note']); ?></td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-outline-primary me-1" onclick="showEditModal(<?php echo htmlspecialchars(json_encode($h)); ?>)">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" onclick="deleteHoliday(<?php echo $h['id']; ?>)">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="holidayModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form method="POST" class="modal-content border-0 shadow">
|
||||
<input type="hidden" name="action" id="modalAction" value="create">
|
||||
<input type="hidden" name="id" id="holidayId">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold text-secondary" id="modalTitle"><?php echo __('add_holiday'); ?></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body pt-3">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted"><?php echo __('doctor'); ?></label>
|
||||
<select name="doctor_id" id="doctorId" class="form-select" required>
|
||||
<option value=""><?php echo __('select') . ' ' . __('doctor'); ?></option>
|
||||
<?php foreach ($doctors as $d): ?>
|
||||
<option value="<?php echo $d['id']; ?>"><?php echo htmlspecialchars($d['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small text-muted"><?php echo __('start_date'); ?></label>
|
||||
<input type="date" name="start_date" id="startDate" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small text-muted"><?php echo __('end_date'); ?></label>
|
||||
<input type="date" name="end_date" id="endDate" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted"><?php echo __('note'); ?></label>
|
||||
<textarea name="note" id="note" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 bg-light rounded-bottom">
|
||||
<button type="button" class="btn btn-secondary shadow-sm me-2" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
|
||||
<button type="submit" class="btn btn-primary shadow-sm px-4"><i class="bi bi-check2-circle me-1"></i> <?php echo __('save'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Form -->
|
||||
<form id="deleteForm" method="POST" style="display:none;">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="id" id="deleteId">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function showCreateModal() {
|
||||
document.getElementById('modalTitle').innerText = '<?php echo __('add_holiday'); ?>';
|
||||
document.getElementById('modalAction').value = 'create';
|
||||
document.getElementById('holidayId').value = '';
|
||||
document.getElementById('doctorId').value = '';
|
||||
document.getElementById('startDate').value = '';
|
||||
document.getElementById('endDate').value = '';
|
||||
document.getElementById('note').value = '';
|
||||
}
|
||||
|
||||
function showEditModal(data) {
|
||||
document.getElementById('modalTitle').innerText = '<?php echo __('edit_holiday'); ?>';
|
||||
document.getElementById('modalAction').value = 'update';
|
||||
document.getElementById('holidayId').value = data.id;
|
||||
document.getElementById('doctorId').value = data.doctor_id;
|
||||
document.getElementById('startDate').value = data.start_date;
|
||||
document.getElementById('endDate').value = data.end_date;
|
||||
document.getElementById('note').value = data.note;
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('holidayModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function deleteHoliday(id) {
|
||||
if (confirm('<?php echo __('are_you_sure_delete_holiday'); ?>')) {
|
||||
document.getElementById('deleteId').value = id;
|
||||
document.getElementById('deleteForm').submit();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,521 +0,0 @@
|
||||
<?php
|
||||
$search_name = $_GET['name'] ?? '';
|
||||
$search_dept = $_GET['department_id'] ?? '';
|
||||
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$where = "WHERE 1=1";
|
||||
$params = [];
|
||||
|
||||
if ($search_name) {
|
||||
$where .= " AND (d.name_en LIKE ? OR d.name_ar LIKE ?)";
|
||||
$params[] = "%$search_name%";
|
||||
$params[] = "%$search_name%";
|
||||
}
|
||||
if ($search_dept) {
|
||||
$where .= " AND d.department_id = ?";
|
||||
$params[] = $search_dept;
|
||||
}
|
||||
|
||||
// Count Total
|
||||
$countQuery = "SELECT COUNT(*) FROM doctors d $where";
|
||||
$stmt = $db->prepare($countQuery);
|
||||
$stmt->execute($params);
|
||||
$totalDoctors = $stmt->fetchColumn();
|
||||
$totalPages = ceil($totalDoctors / $limit);
|
||||
|
||||
// Fetch Data
|
||||
$query = "
|
||||
SELECT d.*, dept.name_$lang as department_name
|
||||
FROM doctors d
|
||||
LEFT JOIN departments dept ON d.department_id = dept.id
|
||||
$where
|
||||
ORDER BY d.id DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$doctors = $stmt->fetchAll();
|
||||
|
||||
// --- AJAX HANDLER ---
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
ob_start();
|
||||
if (empty($doctors)):
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-person-badge display-4 d-block mb-3"></i>
|
||||
<?php echo __('no_doctors_found'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($doctors as $d): ?>
|
||||
<tr>
|
||||
<td class="px-4">
|
||||
<div class="fw-semibold text-dark"><?php echo htmlspecialchars($d['name_'.$lang]); ?></div>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($d['name_'.($lang == 'en' ? 'ar' : 'en')]); ?></small>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($d['specialization_'.$lang]); ?></td>
|
||||
<td>
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-2 py-1">
|
||||
<?php echo htmlspecialchars($d['department_name'] ?: '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small text-secondary"><i class="bi bi-telephone me-1"></i> <?php echo htmlspecialchars($d['tel'] ?: '-'); ?></div>
|
||||
<div class="small text-secondary"><i class="bi bi-envelope me-1"></i> <?php echo htmlspecialchars($d['email'] ?: '-'); ?></div>
|
||||
</td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
onclick="showEditDoctorModal(<?php echo htmlspecialchars(json_encode($d, JSON_UNESCAPED_UNICODE)); ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('edit'); ?>">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-warning py-1 px-2 border-end"
|
||||
onclick="showDoctorHolidays(<?php echo $d['id']; ?>, '<?php echo htmlspecialchars($d['name_'.$lang]); ?>')"
|
||||
data-bs-toggle="tooltip" title="Holidays">
|
||||
<i class="bi bi-calendar-x"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-danger py-1 px-2"
|
||||
onclick="showDeleteDoctorModal(<?php echo $d['id']; ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('delete'); ?>">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif;
|
||||
$table_html = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
if ($totalPages > 1): ?>
|
||||
<div class="d-flex justify-content-between align-items-center p-3 border-top">
|
||||
<div class="text-muted small">
|
||||
<?php echo __('showing'); ?> <?php echo $offset + 1; ?> - <?php echo min($offset + $limit, $totalDoctors); ?> <?php echo __('of'); ?> <?php echo $totalDoctors; ?>
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item <?php echo $page <= 1 ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page - 1; ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$range = 2;
|
||||
$pages_to_show = [];
|
||||
$pages_to_show[] = 1;
|
||||
if ($totalPages > 1) { $pages_to_show[] = $totalPages; }
|
||||
for ($i = $page - $range; $i <= $page + $range; $i++) {
|
||||
if ($i > 1 && $i < $totalPages) { $pages_to_show[] = $i; }
|
||||
}
|
||||
$pages_to_show = array_unique($pages_to_show);
|
||||
sort($pages_to_show);
|
||||
|
||||
$prev_page = 0;
|
||||
foreach ($pages_to_show as $p):
|
||||
if ($prev_page > 0 && $p > $prev_page + 1): ?>
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
<?php endif; ?>
|
||||
<li class="page-item <?php echo $page == $p ? 'active' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $p; ?>">
|
||||
<?php echo $p; ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$prev_page = $p;
|
||||
endforeach;
|
||||
?>
|
||||
<li class="page-item <?php echo $page >= $totalPages ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page + 1; ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif;
|
||||
$pagination_html = ob_get_clean();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['html' => $table_html, 'pagination' => $pagination_html]);
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h3 class="fw-bold text-secondary"><?php echo __('doctors'); ?></h3>
|
||||
<button class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#addDoctorModal">
|
||||
<i class="bi bi-person-plus-fill me-1"></i> <?php echo __('add_doctor'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<form id="doctorsSearchForm" class="row g-3" onsubmit="return false;">
|
||||
<div class="col-md-6">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0 text-muted"><i class="bi bi-search"></i></span>
|
||||
<input type="text" name="name" id="doctorSearchName" class="form-control bg-light border-start-0" placeholder="<?php echo __('name'); ?>" value="<?php echo htmlspecialchars($search_name); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="department_id" id="doctorSearchDept" class="form-select bg-light">
|
||||
<option value=""><?php echo __('department'); ?> (<?php echo __('all'); ?>)</option>
|
||||
<?php foreach ($all_departments as $dept): ?>
|
||||
<option value="<?php echo $dept['id']; ?>" <?php echo $search_dept == $dept['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($dept['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-secondary w-100" onclick="fetchDoctors(1)"><?php echo __('search'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light text-secondary">
|
||||
<tr>
|
||||
<th class="px-4 py-3"><?php echo __('name'); ?></th>
|
||||
<th class="py-3"><?php echo __('specialization'); ?></th>
|
||||
<th class="py-3"><?php echo __('department'); ?></th>
|
||||
<th class="py-3"><?php echo __('contact'); ?></th>
|
||||
<th class="py-3 text-end px-4"><?php echo __('actions'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="doctorsTableBody">
|
||||
<?php if (empty($doctors)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-person-badge display-4 d-block mb-3"></i>
|
||||
<?php echo __('no_doctors_found'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($doctors as $d): ?>
|
||||
<tr>
|
||||
<td class="px-4">
|
||||
<div class="fw-semibold text-dark"><?php echo htmlspecialchars($d['name_'.$lang]); ?></div>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($d['name_'.($lang == 'en' ? 'ar' : 'en')]); ?></small>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($d['specialization_'.$lang]); ?></td>
|
||||
<td>
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-2 py-1">
|
||||
<?php echo htmlspecialchars($d['department_name'] ?: '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small text-secondary"><i class="bi bi-telephone me-1"></i> <?php echo htmlspecialchars($d['tel'] ?: '-'); ?></div>
|
||||
<div class="small text-secondary"><i class="bi bi-envelope me-1"></i> <?php echo htmlspecialchars($d['email'] ?: '-'); ?></div>
|
||||
</td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
onclick="showEditDoctorModal(<?php echo htmlspecialchars(json_encode($d, JSON_UNESCAPED_UNICODE)); ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('edit'); ?>">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-warning py-1 px-2 border-end"
|
||||
onclick="showDoctorHolidays(<?php echo $d['id']; ?>, '<?php echo htmlspecialchars($d['name_'.$lang]); ?>')"
|
||||
data-bs-toggle="tooltip" title="Holidays">
|
||||
<i class="bi bi-calendar-x"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-danger py-1 px-2"
|
||||
onclick="showDeleteDoctorModal(<?php echo $d['id']; ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('delete'); ?>">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div id="doctorsPagination">
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="d-flex justify-content-between align-items-center p-3 border-top">
|
||||
<div class="text-muted small">
|
||||
<?php echo __('showing'); ?> <?php echo $offset + 1; ?> - <?php echo min($offset + $limit, $totalDoctors); ?> <?php echo __('of'); ?> <?php echo $totalDoctors; ?>
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item <?php echo $page <= 1 ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page - 1; ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$range = 2;
|
||||
$pages_to_show = [];
|
||||
$pages_to_show[] = 1;
|
||||
if ($totalPages > 1) { $pages_to_show[] = $totalPages; }
|
||||
for ($i = $page - $range; $i <= $page + $range; $i++) {
|
||||
if ($i > 1 && $i < $totalPages) { $pages_to_show[] = $i; }
|
||||
}
|
||||
$pages_to_show = array_unique($pages_to_show);
|
||||
sort($pages_to_show);
|
||||
|
||||
$prev_page = 0;
|
||||
foreach ($pages_to_show as $p):
|
||||
if ($prev_page > 0 && $p > $prev_page + 1): ?>
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
<?php endif; ?>
|
||||
<li class="page-item <?php echo $page == $p ? 'active' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $p; ?>">
|
||||
<?php echo $p; ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$prev_page = $p;
|
||||
endforeach;
|
||||
?>
|
||||
<li class="page-item <?php echo $page >= $totalPages ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page + 1; ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Doctor Holidays Modal -->
|
||||
<div class="modal fade" id="doctorHolidaysModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold text-secondary" id="doctorHolidaysTitle">Doctor Holidays</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body pt-3">
|
||||
<input type="hidden" id="holidayDoctorId">
|
||||
<form id="addHolidayForm" onsubmit="addDoctorHoliday(); return false;">
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-md-5">
|
||||
<label class="small text-muted">Start Date</label>
|
||||
<input type="date" id="holidayStartDate" class="form-control form-control-sm" required>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label class="small text-muted">End Date</label>
|
||||
<input type="date" id="holidayEndDate" class="form-control form-control-sm" required>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary btn-sm w-100">Add</button>
|
||||
</div>
|
||||
<div class="col-12 mt-1">
|
||||
<input type="text" id="holidayNote" class="form-control form-control-sm" placeholder="Note (optional)">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h6 class="small text-muted text-uppercase fw-bold mb-2">Current Holidays</h6>
|
||||
<div class="table-responsive" style="max-height: 200px; overflow-y: auto;">
|
||||
<table class="table table-sm table-bordered mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Start</th>
|
||||
<th>End</th>
|
||||
<th>Note</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="holidaysListBody">
|
||||
<tr><td colspan="4" class="text-center text-muted">Loading...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchName = document.getElementById('doctorSearchName');
|
||||
const searchDept = document.getElementById('doctorSearchDept');
|
||||
const tableBody = document.getElementById('doctorsTableBody');
|
||||
const paginationContainer = document.getElementById('doctorsPagination');
|
||||
|
||||
let timeout = null;
|
||||
|
||||
if (searchName) {
|
||||
searchName.addEventListener('input', function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => fetchDoctors(1), 300);
|
||||
});
|
||||
}
|
||||
|
||||
if (searchDept) {
|
||||
searchDept.addEventListener('change', function() {
|
||||
fetchDoctors(1);
|
||||
});
|
||||
}
|
||||
|
||||
// Event delegation for pagination clicks
|
||||
if (paginationContainer) {
|
||||
paginationContainer.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const link = e.target.closest('.page-link');
|
||||
if (link && !link.parentElement.classList.contains('disabled')) {
|
||||
const page = link.getAttribute('data-page');
|
||||
if (page) fetchDoctors(page);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function fetchDoctors(page) {
|
||||
const name = document.getElementById('doctorSearchName').value;
|
||||
const dept = document.getElementById('doctorSearchDept').value;
|
||||
const tableBody = document.getElementById('doctorsTableBody');
|
||||
const paginationContainer = document.getElementById('doctorsPagination');
|
||||
|
||||
if (tableBody) tableBody.style.opacity = '0.5';
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (name) params.append('name', name);
|
||||
if (dept) params.append('department_id', dept);
|
||||
params.append('page', page);
|
||||
params.append('ajax_search', '1');
|
||||
|
||||
fetch('doctors.php?' + params.toString())
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (tableBody) {
|
||||
tableBody.innerHTML = data.html;
|
||||
tableBody.style.opacity = '1';
|
||||
}
|
||||
if (paginationContainer) {
|
||||
paginationContainer.innerHTML = data.pagination;
|
||||
}
|
||||
|
||||
// Re-initialize tooltips
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching doctors:', error);
|
||||
if (tableBody) tableBody.style.opacity = '1';
|
||||
});
|
||||
}
|
||||
|
||||
function showDoctorHolidays(doctorId, doctorName) {
|
||||
document.getElementById('holidayDoctorId').value = doctorId;
|
||||
document.getElementById('doctorHolidaysTitle').innerText = 'Holidays - ' + doctorName;
|
||||
|
||||
// Clear form
|
||||
document.getElementById('holidayStartDate').value = '';
|
||||
document.getElementById('holidayEndDate').value = '';
|
||||
document.getElementById('holidayNote').value = '';
|
||||
|
||||
// Fetch holidays
|
||||
fetchHolidays(doctorId);
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('doctorHolidaysModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function fetchHolidays(doctorId) {
|
||||
fetch('api/doctor_holidays.php?doctor_id=' + doctorId)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const tbody = document.getElementById('holidaysListBody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (data.success && data.holidays.length > 0) {
|
||||
data.holidays.forEach(h => {
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td>${h.start_date}</td>
|
||||
<td>${h.end_date}</td>
|
||||
<td>${h.note || '-'}</td>
|
||||
<td class="text-center">
|
||||
<button class="btn btn-link text-danger p-0" onclick="deleteDoctorHoliday(${h.id})">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
} else {
|
||||
tbody.innerHTML = '<tr><td colspan="4" class="text-center text-muted">No holidays found.</td></tr>';
|
||||
}
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
function addDoctorHoliday() {
|
||||
const doctorId = document.getElementById('holidayDoctorId').value;
|
||||
const start = document.getElementById('holidayStartDate').value;
|
||||
const end = document.getElementById('holidayEndDate').value;
|
||||
const note = document.getElementById('holidayNote').value;
|
||||
|
||||
if (!start || !end) return;
|
||||
|
||||
fetch('api/doctor_holidays.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
action: 'create',
|
||||
doctor_id: doctorId,
|
||||
start_date: start,
|
||||
end_date: end,
|
||||
note: note
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
fetchHolidays(doctorId); // Refresh list
|
||||
document.getElementById('holidayStartDate').value = '';
|
||||
document.getElementById('holidayEndDate').value = '';
|
||||
document.getElementById('holidayNote').value = '';
|
||||
} else {
|
||||
alert('Error adding holiday: ' + (data.error || 'Unknown error'));
|
||||
}
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
function deleteDoctorHoliday(id) {
|
||||
if (!confirm('Delete this holiday?')) return;
|
||||
|
||||
const doctorId = document.getElementById('holidayDoctorId').value;
|
||||
|
||||
fetch('api/doctor_holidays.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
action: 'delete',
|
||||
id: id
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
fetchHolidays(doctorId); // Refresh list
|
||||
} else {
|
||||
alert('Error deleting holiday: ' + (data.error || 'Unknown error'));
|
||||
}
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
</script>
|
||||
@ -22,8 +22,8 @@ $query = "
|
||||
n.name_$lang as nurse_name
|
||||
FROM appointments a
|
||||
JOIN patients p ON a.patient_id = p.id
|
||||
LEFT JOIN doctors d ON a.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON a.nurse_id = n.id
|
||||
LEFT JOIN employees d ON a.doctor_id = d.id
|
||||
LEFT JOIN employees n ON a.nurse_id = n.id
|
||||
$where
|
||||
ORDER BY a.start_time ASC
|
||||
";
|
||||
|
||||
@ -66,7 +66,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Leave Requests</h1>
|
||||
<button class="btn btn-primary btn-sm" data-toggle="modal" data-target="#addLeaveModal">
|
||||
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addLeaveModal">
|
||||
<i class="fas fa-plus"></i> New Request
|
||||
</button>
|
||||
</div>
|
||||
@ -74,14 +74,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<!-- Filter -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="form-inline">
|
||||
<select name="status" class="form-control mr-2 mb-2">
|
||||
<form method="GET" class="d-flex align-items-center">
|
||||
<select name="status" class="form-select me-2" style="width: auto;">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="Pending" <?php echo (isset($_GET['status']) && $_GET['status'] == 'Pending') ? 'selected' : ''; ?>>Pending</option>
|
||||
<option value="Approved" <?php echo (isset($_GET['status']) && $_GET['status'] == 'Approved') ? 'selected' : ''; ?>>Approved</option>
|
||||
<option value="Rejected" <?php echo (isset($_GET['status']) && $_GET['status'] == 'Rejected') ? 'selected' : ''; ?>>Rejected</option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-primary mb-2">Filter</button>
|
||||
<button type="submit" class="btn btn-primary">Filter</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -113,7 +113,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<td><?php echo $req['days']; ?></td>
|
||||
<td><?php echo htmlspecialchars($req['reason']); ?></td>
|
||||
<td>
|
||||
<span class="badge badge-<?php
|
||||
<span class="badge bg-<?php
|
||||
echo $req['status'] == 'Approved' ? 'success' :
|
||||
($req['status'] == 'Pending' ? 'warning' : 'danger');
|
||||
?>">
|
||||
@ -163,55 +163,53 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</div>
|
||||
|
||||
<!-- Add Modal -->
|
||||
<div class="modal fade" id="addLeaveModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal fade" id="addLeaveModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="POST">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Request Leave</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="add_leave" value="1">
|
||||
<div class="form-group">
|
||||
<label>Employee</label>
|
||||
<select name="employee_id" class="form-control" required>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Employee</label>
|
||||
<select name="employee_id" class="form-select" required>
|
||||
<?php foreach ($employees as $id => $name): ?>
|
||||
<option value="<?php echo $id; ?>"><?php echo htmlspecialchars($name); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Leave Type</label>
|
||||
<select name="leave_type" class="form-control">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Leave Type</label>
|
||||
<select name="leave_type" class="form-select">
|
||||
<option value="Annual">Annual</option>
|
||||
<option value="Sick">Sick</option>
|
||||
<option value="Casual">Casual</option>
|
||||
<option value="Unpaid">Unpaid</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<label>Start Date</label>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Start Date</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label>End Date</label>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">End Date</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Reason</label>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Reason</label>
|
||||
<textarea name="reason" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,468 +0,0 @@
|
||||
<?php
|
||||
$search_name = $_GET['name'] ?? '';
|
||||
$search_dept = $_GET['department_id'] ?? '';
|
||||
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$limit = 10;
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
$where = "WHERE 1=1";
|
||||
$params = [];
|
||||
|
||||
if ($search_name) {
|
||||
$where .= " AND (n.name_en LIKE ? OR n.name_ar LIKE ?)";
|
||||
$params[] = "%$search_name%";
|
||||
$params[] = "%$search_name%";
|
||||
}
|
||||
if ($search_dept) {
|
||||
$where .= " AND n.department_id = ?";
|
||||
$params[] = $search_dept;
|
||||
}
|
||||
|
||||
// Count Total
|
||||
$countQuery = "SELECT COUNT(*) FROM nurses n $where";
|
||||
$stmt = $db->prepare($countQuery);
|
||||
$stmt->execute($params);
|
||||
$totalNurses = $stmt->fetchColumn();
|
||||
$totalPages = ceil($totalNurses / $limit);
|
||||
|
||||
// Fetch Data
|
||||
$query = "
|
||||
SELECT n.*, dept.name_$lang as department_name
|
||||
FROM nurses n
|
||||
LEFT JOIN departments dept ON n.department_id = dept.id
|
||||
$where
|
||||
ORDER BY n.id DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
|
||||
$stmt = $db->prepare($query);
|
||||
$stmt->execute($params);
|
||||
$nurses = $stmt->fetchAll();
|
||||
|
||||
// --- AJAX HANDLER ---
|
||||
if (isset($_GET['ajax_search'])) {
|
||||
ob_start();
|
||||
if (empty($nurses)):
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-person-heart display-4 d-block mb-3"></i>
|
||||
<?php echo __('no_nurses_found'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($nurses as $nurse): ?>
|
||||
<tr>
|
||||
<td class="px-4">
|
||||
<div class="fw-semibold text-dark"><?php echo htmlspecialchars($nurse['name_'.$lang]); ?></div>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($nurse['name_'.($lang == 'en' ? 'ar' : 'en')]); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-2 py-1">
|
||||
<?php echo htmlspecialchars($nurse['department_name'] ?: '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small text-secondary"><i class="bi bi-telephone me-1"></i> <?php echo htmlspecialchars($nurse['tel'] ?: '-'); ?></div>
|
||||
<div class="small text-secondary"><i class="bi bi-envelope me-1"></i> <?php echo htmlspecialchars($nurse['email'] ?: '-'); ?></div>
|
||||
</td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
onclick="showEditNurseModal(<?php echo htmlspecialchars(json_encode($nurse, JSON_UNESCAPED_UNICODE)); ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('edit'); ?>">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-danger py-1 px-2"
|
||||
onclick="showDeleteNurseModal(<?php echo $nurse['id']; ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('delete'); ?>">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif;
|
||||
$table_html = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
if ($totalPages > 1): ?>
|
||||
<div class="d-flex justify-content-between align-items-center p-3 border-top">
|
||||
<div class="text-muted small">
|
||||
<?php echo __('showing'); ?> <?php echo $offset + 1; ?> - <?php echo min($offset + $limit, $totalNurses); ?> <?php echo __('of'); ?> <?php echo $totalNurses; ?>
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item <?php echo $page <= 1 ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page - 1; ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$range = 2;
|
||||
$pages_to_show = [];
|
||||
$pages_to_show[] = 1;
|
||||
if ($totalPages > 1) { $pages_to_show[] = $totalPages; }
|
||||
for ($i = $page - $range; $i <= $page + $range; $i++) {
|
||||
if ($i > 1 && $i < $totalPages) { $pages_to_show[] = $i; }
|
||||
}
|
||||
$pages_to_show = array_unique($pages_to_show);
|
||||
sort($pages_to_show);
|
||||
|
||||
$prev_page = 0;
|
||||
foreach ($pages_to_show as $p):
|
||||
if ($prev_page > 0 && $p > $prev_page + 1): ?>
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
<?php endif; ?>
|
||||
<li class="page-item <?php echo $page == $p ? 'active' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $p; ?>">
|
||||
<?php echo $p; ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$prev_page = $p;
|
||||
endforeach;
|
||||
?>
|
||||
<li class="page-item <?php echo $page >= $totalPages ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page + 1; ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif;
|
||||
$pagination_html = ob_get_clean();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['html' => $table_html, 'pagination' => $pagination_html]);
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h3 class="fw-bold text-secondary"><?php echo __('nurses'); ?></h3>
|
||||
<button class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#addNurseModal" onclick="resetNurseModal()">
|
||||
<i class="bi bi-person-plus-fill me-1"></i> <?php echo __('add_nurse'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<form id="nursesSearchForm" class="row g-3" onsubmit="return false;">
|
||||
<div class="col-md-6">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-light border-end-0 text-muted"><i class="bi bi-search"></i></span>
|
||||
<input type="text" name="name" id="nurseSearchName" class="form-control bg-light border-start-0" placeholder="<?php echo __('name'); ?>" value="<?php echo htmlspecialchars($search_name); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="department_id" id="nurseSearchDept" class="form-select bg-light">
|
||||
<option value=""><?php echo __('department'); ?> (<?php echo __('all'); ?>)</option>
|
||||
<?php foreach ($all_departments as $dept): ?>
|
||||
<option value="<?php echo $dept['id']; ?>" <?php echo $search_dept == $dept['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($dept['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-secondary w-100" onclick="fetchNurses(1)"><?php echo __('search'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light text-secondary">
|
||||
<tr>
|
||||
<th class="px-4 py-3"><?php echo __('name'); ?></th>
|
||||
<th class="py-3"><?php echo __('department'); ?></th>
|
||||
<th class="py-3"><?php echo __('contact'); ?></th>
|
||||
<th class="py-3 text-end px-4"><?php echo __('actions'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="nursesTableBody">
|
||||
<?php if (empty($nurses)): ?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-person-heart display-4 d-block mb-3"></i>
|
||||
<?php echo __('no_nurses_found'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($nurses as $nurse): ?>
|
||||
<tr>
|
||||
<td class="px-4">
|
||||
<div class="fw-semibold text-dark"><?php echo htmlspecialchars($nurse['name_'.$lang]); ?></div>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($nurse['name_'.($lang == 'en' ? 'ar' : 'en')]); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-2 py-1">
|
||||
<?php echo htmlspecialchars($nurse['department_name'] ?: '-'); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small text-secondary"><i class="bi bi-telephone me-1"></i> <?php echo htmlspecialchars($nurse['tel'] ?: '-'); ?></div>
|
||||
<div class="small text-secondary"><i class="bi bi-envelope me-1"></i> <?php echo htmlspecialchars($nurse['email'] ?: '-'); ?></div>
|
||||
</td>
|
||||
<td class="text-end px-4">
|
||||
<div class="btn-group shadow-sm border rounded bg-white">
|
||||
<button class="btn btn-link text-primary py-1 px-2 border-end"
|
||||
onclick="showEditNurseModal(<?php echo htmlspecialchars(json_encode($nurse, JSON_UNESCAPED_UNICODE)); ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('edit'); ?>">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button class="btn btn-link text-danger py-1 px-2"
|
||||
onclick="showDeleteNurseModal(<?php echo $nurse['id']; ?>)"
|
||||
data-bs-toggle="tooltip" title="<?php echo __('delete'); ?>">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div id="nursesPagination">
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="d-flex justify-content-between align-items-center p-3 border-top">
|
||||
<div class="text-muted small">
|
||||
<?php echo __('showing'); ?> <?php echo $offset + 1; ?> - <?php echo min($offset + $limit, $totalNurses); ?> <?php echo __('of'); ?> <?php echo $totalNurses; ?>
|
||||
</div>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item <?php echo $page <= 1 ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page - 1; ?>" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$range = 2;
|
||||
$pages_to_show = [];
|
||||
$pages_to_show[] = 1;
|
||||
if ($totalPages > 1) { $pages_to_show[] = $totalPages; }
|
||||
for ($i = $page - $range; $i <= $page + $range; $i++) {
|
||||
if ($i > 1 && $i < $totalPages) { $pages_to_show[] = $i; }
|
||||
}
|
||||
$pages_to_show = array_unique($pages_to_show);
|
||||
sort($pages_to_show);
|
||||
|
||||
$prev_page = 0;
|
||||
foreach ($pages_to_show as $p):
|
||||
if ($prev_page > 0 && $p > $prev_page + 1): ?>
|
||||
<li class="page-item disabled"><span class="page-link">...</span></li>
|
||||
<?php endif; ?>
|
||||
<li class="page-item <?php echo $page == $p ? 'active' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $p; ?>">
|
||||
<?php echo $p; ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$prev_page = $p;
|
||||
endforeach;
|
||||
?>
|
||||
<li class="page-item <?php echo $page >= $totalPages ? 'disabled' : ''; ?>">
|
||||
<a class="page-link" href="#" data-page="<?php echo $page + 1; ?>" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add/Edit Nurse Modal -->
|
||||
<div class="modal fade" id="addNurseModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="nurseModalTitle"><?php echo __('add_nurse'); ?></h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="POST" action="">
|
||||
<input type="hidden" name="action" id="nurseAction" value="add_nurse">
|
||||
<input type="hidden" name="id" id="nurseId">
|
||||
<div class="modal-body p-4">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('name_en'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="name_en" id="nurseNameEn" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('name_ar'); ?> <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="name_ar" id="nurseNameAr" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('email'); ?></label>
|
||||
<input type="email" class="form-control" name="email" id="nurseEmail">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('tel'); ?></label>
|
||||
<input type="text" class="form-control" name="tel" id="nurseTel">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?php echo __('department'); ?></label>
|
||||
<select class="form-select" name="department_id" id="nurseDeptId">
|
||||
<option value=""><?php echo __('select_department'); ?></option>
|
||||
<?php foreach ($all_departments as $dept): ?>
|
||||
<option value="<?php echo $dept['id']; ?>">
|
||||
<?php echo htmlspecialchars($dept['name_' . $lang]); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo __('close'); ?></button>
|
||||
<button type="submit" class="btn btn-primary"><?php echo __('save'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Nurse Modal -->
|
||||
<div class="modal fade" id="deleteNurseModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title"><?php echo __('delete_nurse'); ?></h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="POST" action="">
|
||||
<input type="hidden" name="action" value="delete_nurse">
|
||||
<input type="hidden" name="id" id="deleteNurseId">
|
||||
<div class="modal-body p-4 text-center">
|
||||
<div class="mb-3 text-danger">
|
||||
<i class="bi bi-exclamation-triangle display-1"></i>
|
||||
</div>
|
||||
<p class="mb-0 fs-5"><?php echo __('are_you_sure_delete'); ?></p>
|
||||
<p class="text-muted small"><?php echo __('action_cannot_be_undone'); ?></p>
|
||||
</div>
|
||||
<div class="modal-footer bg-light justify-content-center">
|
||||
<button type="button" class="btn btn-secondary px-4" data-bs-dismiss="modal"><?php echo __('cancel'); ?></button>
|
||||
<button type="submit" class="btn btn-danger px-4"><?php echo __('delete'); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchName = document.getElementById('nurseSearchName');
|
||||
const searchDept = document.getElementById('nurseSearchDept');
|
||||
const tableBody = document.getElementById('nursesTableBody');
|
||||
const paginationContainer = document.getElementById('nursesPagination');
|
||||
|
||||
let timeout = null;
|
||||
|
||||
if (searchName) {
|
||||
searchName.addEventListener('input', function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => fetchNurses(1), 300);
|
||||
});
|
||||
}
|
||||
|
||||
if (searchDept) {
|
||||
searchDept.addEventListener('change', function() {
|
||||
fetchNurses(1);
|
||||
});
|
||||
}
|
||||
|
||||
if (paginationContainer) {
|
||||
paginationContainer.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const link = e.target.closest('.page-link');
|
||||
if (link && !link.parentElement.classList.contains('disabled')) {
|
||||
const page = link.getAttribute('data-page');
|
||||
if (page) fetchNurses(page);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function fetchNurses(page) {
|
||||
const name = document.getElementById('nurseSearchName').value;
|
||||
const dept = document.getElementById('nurseSearchDept').value;
|
||||
const tableBody = document.getElementById('nursesTableBody');
|
||||
const paginationContainer = document.getElementById('nursesPagination');
|
||||
|
||||
if (tableBody) tableBody.style.opacity = '0.5';
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (name) params.append('name', name);
|
||||
if (dept) params.append('department_id', dept);
|
||||
params.append('page', page);
|
||||
params.append('ajax_search', '1');
|
||||
|
||||
fetch('nurses.php?' + params.toString())
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (tableBody) {
|
||||
tableBody.innerHTML = data.html;
|
||||
tableBody.style.opacity = '1';
|
||||
}
|
||||
if (paginationContainer) {
|
||||
paginationContainer.innerHTML = data.pagination;
|
||||
}
|
||||
|
||||
// Re-initialize tooltips
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching nurses:', error);
|
||||
if (tableBody) tableBody.style.opacity = '1';
|
||||
});
|
||||
}
|
||||
|
||||
function resetNurseModal() {
|
||||
document.getElementById('nurseModalTitle').textContent = '<?php echo __('add_nurse'); ?>';
|
||||
document.getElementById('nurseAction').value = 'add_nurse';
|
||||
document.getElementById('nurseId').value = '';
|
||||
|
||||
document.getElementById('nurseNameEn').value = '';
|
||||
document.getElementById('nurseNameAr').value = '';
|
||||
document.getElementById('nurseEmail').value = '';
|
||||
document.getElementById('nurseTel').value = '';
|
||||
document.getElementById('nurseDeptId').value = '';
|
||||
}
|
||||
|
||||
function showEditNurseModal(nurse) {
|
||||
document.getElementById('nurseModalTitle').textContent = '<?php echo __('edit_nurse'); ?>';
|
||||
document.getElementById('nurseAction').value = 'edit_nurse';
|
||||
document.getElementById('nurseId').value = nurse.id;
|
||||
|
||||
document.getElementById('nurseNameEn').value = nurse.name_en;
|
||||
document.getElementById('nurseNameAr').value = nurse.name_ar;
|
||||
document.getElementById('nurseEmail').value = nurse.email;
|
||||
document.getElementById('nurseTel').value = nurse.tel;
|
||||
document.getElementById('nurseDeptId').value = nurse.department_id || '';
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('addNurseModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function showDeleteNurseModal(id) {
|
||||
document.getElementById('deleteNurseId').value = id;
|
||||
var modal = new bootstrap.Modal(document.getElementById('deleteNurseModal'));
|
||||
modal.show();
|
||||
}
|
||||
</script>
|
||||
@ -4,7 +4,12 @@
|
||||
// Fetch Departments
|
||||
$departments = $db->query("SELECT * FROM departments")->fetchAll(PDO::FETCH_ASSOC);
|
||||
// Fetch Doctors
|
||||
$doctors = $db->query("SELECT * FROM doctors")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$doctors = $db->query("
|
||||
SELECT e.*
|
||||
FROM employees e
|
||||
JOIN positions p ON e.position_id = p.id
|
||||
WHERE UPPER(p.name_en) = 'DOCTOR'
|
||||
")->fetchAll(PDO::FETCH_ASSOC);
|
||||
// Fetch Patients (Limit 50 for initial load, preferably use AJAX for real search)
|
||||
$patients = $db->query("SELECT * FROM patients ORDER BY id DESC LIMIT 50")->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -253,4 +258,4 @@ function issueToken() {
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
@ -35,10 +35,11 @@ $stmt->execute([$start_date, $end_date]);
|
||||
$revenue_trend = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 6. Visits by Doctor (Top 5)
|
||||
// Updated to join employees
|
||||
$stmt = $db->prepare("
|
||||
SELECT d.name_$lang as doctor_name, COUNT(v.id) as count
|
||||
FROM visits v
|
||||
JOIN doctors d ON v.doctor_id = d.id
|
||||
JOIN employees d ON v.doctor_id = d.id
|
||||
WHERE DATE(v.visit_date) BETWEEN ? AND ?
|
||||
GROUP BY v.doctor_id
|
||||
ORDER BY count DESC
|
||||
@ -53,13 +54,14 @@ $stmt->execute([$start_date, $end_date]);
|
||||
$patients_by_gender = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
// 8. Department Revenue Report
|
||||
// Updated to join employees
|
||||
$stmt = $db->prepare("
|
||||
SELECT d.name_$lang as name,
|
||||
COUNT(DISTINCT b.visit_id) as visit_count,
|
||||
SUM(b.total_amount) as revenue
|
||||
FROM bills b
|
||||
JOIN visits v ON b.visit_id = v.id
|
||||
JOIN doctors doc ON v.doctor_id = doc.id
|
||||
JOIN employees doc ON v.doctor_id = doc.id
|
||||
JOIN departments d ON doc.department_id = d.id
|
||||
WHERE b.status = 'Paid' AND DATE(b.created_at) BETWEEN ? AND ?
|
||||
GROUP BY d.id
|
||||
@ -69,6 +71,7 @@ $stmt->execute([$start_date, $end_date]);
|
||||
$dept_revenue = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// 9. Doctor Revenue Report
|
||||
// Updated to join employees
|
||||
$stmt = $db->prepare("
|
||||
SELECT doc.name_$lang as name,
|
||||
d.name_$lang as department_name,
|
||||
@ -76,7 +79,7 @@ $stmt = $db->prepare("
|
||||
SUM(b.total_amount) as revenue
|
||||
FROM bills b
|
||||
JOIN visits v ON b.visit_id = v.id
|
||||
JOIN doctors doc ON v.doctor_id = doc.id
|
||||
JOIN employees doc ON v.doctor_id = doc.id
|
||||
LEFT JOIN departments d ON doc.department_id = d.id
|
||||
WHERE b.status = 'Paid' AND DATE(b.created_at) BETWEEN ? AND ?
|
||||
GROUP BY doc.id
|
||||
|
||||
@ -14,7 +14,10 @@ if ($search_patient) {
|
||||
$params[] = "%$search_patient%";
|
||||
}
|
||||
if ($search_doctor) {
|
||||
$where .= " AND (d.name_en LIKE ? OR d.name_ar LIKE ? OR n.name_en LIKE ? OR n.name_ar LIKE ?)";
|
||||
$where .= " AND (
|
||||
doc.name_en LIKE ? OR doc.name_ar LIKE ? OR
|
||||
nur.name_en LIKE ? OR nur.name_ar LIKE ?
|
||||
)";
|
||||
$params[] = "%$search_doctor%";
|
||||
$params[] = "%$search_doctor%";
|
||||
$params[] = "%$search_doctor%";
|
||||
@ -30,8 +33,8 @@ $countQuery = "
|
||||
SELECT COUNT(*)
|
||||
FROM visits v
|
||||
JOIN patients p ON v.patient_id = p.id
|
||||
LEFT JOIN doctors d ON v.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON v.nurse_id = n.id
|
||||
LEFT JOIN employees doc ON v.doctor_id = doc.id
|
||||
LEFT JOIN employees nur ON v.nurse_id = nur.id
|
||||
$where";
|
||||
$stmt = $db->prepare($countQuery);
|
||||
$stmt->execute($params);
|
||||
@ -42,12 +45,12 @@ $totalPages = ceil($totalVisits / $limit);
|
||||
$query = "
|
||||
SELECT v.*,
|
||||
p.name as patient_name, p.dob as patient_dob, p.gender as patient_gender,
|
||||
d.name_$lang as doctor_name,
|
||||
n.name_$lang as nurse_name
|
||||
doc.name_$lang as doctor_name,
|
||||
nur.name_$lang as nurse_name
|
||||
FROM visits v
|
||||
JOIN patients p ON v.patient_id = p.id
|
||||
LEFT JOIN doctors d ON v.doctor_id = d.id
|
||||
LEFT JOIN nurses n ON v.nurse_id = n.id
|
||||
LEFT JOIN employees doc ON v.doctor_id = doc.id
|
||||
LEFT JOIN employees nur ON v.nurse_id = nur.id
|
||||
$where
|
||||
ORDER BY v.visit_date DESC
|
||||
LIMIT $limit OFFSET $offset";
|
||||
|
||||
17
lang.php
17
lang.php
@ -338,12 +338,22 @@ $translations = [
|
||||
'delete_patient' => 'Delete Patient',
|
||||
'confirm_delete' => 'Are you sure you want to delete',
|
||||
'add_doctor' => 'Add Doctor',
|
||||
'edit_doctor' => 'Edit Doctor',
|
||||
'specialization_en' => 'Specialization (English)',
|
||||
'specialization_ar' => 'Specialization (Arabic)',
|
||||
'edit_doctor' => 'Edit Doctor',
|
||||
'hr_management' => 'HR Management',
|
||||
'attendance' => 'Attendance',
|
||||
'leave_requests' => 'Leave Requests',
|
||||
'add_employee' => 'Add Employee',
|
||||
'edit_employee' => 'Edit Employee',
|
||||
'delete_employee' => 'Delete Employee',
|
||||
'select_position' => 'Select Position',
|
||||
'no_employees_found' => 'No employees found',
|
||||
'add_employee' => 'Add Employee',
|
||||
'edit_employee' => 'Edit Employee',
|
||||
'delete_employee' => 'Delete Employee',
|
||||
'select_position' => 'Select Position',
|
||||
'no_employees_found' => 'No employees found',
|
||||
],
|
||||
'ar' => [
|
||||
'dashboard' => 'لوحة التحكم',
|
||||
@ -689,5 +699,10 @@ $translations = [
|
||||
'hr_management' => 'إدارة الموارد البشرية',
|
||||
'attendance' => 'الحضور والانصراف',
|
||||
'leave_requests' => 'طلبات الإجازة',
|
||||
'add_employee' => 'إضافة موظف',
|
||||
'edit_employee' => 'تعديل موظف',
|
||||
'delete_employee' => 'حذف موظف',
|
||||
'select_position' => 'اختر المسمى الوظيفي',
|
||||
'no_employees_found' => 'لم يتم العثور على موظفين',
|
||||
]
|
||||
];
|
||||
|
||||
17
nurses.php
17
nurses.php
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
$section = 'nurses';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$db = db();
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
require_once __DIR__ . '/includes/actions.php';
|
||||
require_once __DIR__ . '/includes/common_data.php';
|
||||
require_once __DIR__ . '/includes/layout/header.php';
|
||||
require_once __DIR__ . '/includes/pages/nurses.php';
|
||||
require_once __DIR__ . '/includes/layout/footer.php';
|
||||
?>
|
||||
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/helpers.php';
|
||||
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
check_auth();
|
||||
|
||||
$lang = $_SESSION['lang'] ?? 'en';
|
||||
@ -14,7 +14,8 @@ $db = db();
|
||||
// Fetch Doctor Name if filtered
|
||||
$doctor_name = '';
|
||||
if ($doctor_id) {
|
||||
$stmt = $db->prepare("SELECT name_$lang FROM doctors WHERE id = ?");
|
||||
// doctor_id is now employee_id
|
||||
$stmt = $db->prepare("SELECT name_$lang FROM employees WHERE id = ?");
|
||||
$stmt->execute([$doctor_id]);
|
||||
$doctor_name = $stmt->fetchColumn();
|
||||
}
|
||||
@ -22,8 +23,8 @@ if ($doctor_id) {
|
||||
// Fetch Holidays for the date
|
||||
$holidays_on_date = [];
|
||||
if ($doctor_id) {
|
||||
// Specific doctor holiday check
|
||||
$stmt = $db->prepare("SELECT note FROM doctor_holidays WHERE doctor_id = ? AND ? BETWEEN start_date AND end_date");
|
||||
// Specific doctor holiday check (using leave_requests)
|
||||
$stmt = $db->prepare("SELECT reason FROM leave_requests WHERE employee_id = ? AND status = 'Approved' AND ? BETWEEN start_date AND end_date");
|
||||
$stmt->execute([$doctor_id, $date]);
|
||||
$holiday_note = $stmt->fetchColumn();
|
||||
if ($holiday_note !== false) {
|
||||
@ -33,12 +34,15 @@ if ($doctor_id) {
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// All doctors holiday check
|
||||
// All doctors holiday check (using leave_requests and filtering by position Doctor)
|
||||
$stmt = $db->prepare("
|
||||
SELECT d.name_$lang as doctor_name, h.note
|
||||
FROM doctor_holidays h
|
||||
JOIN doctors d ON h.doctor_id = d.id
|
||||
WHERE ? BETWEEN h.start_date AND h.end_date
|
||||
SELECT e.name_$lang as doctor_name, lr.reason as note
|
||||
FROM leave_requests lr
|
||||
JOIN employees e ON lr.employee_id = e.id
|
||||
JOIN positions p ON e.position_id = p.id
|
||||
WHERE lr.status = 'Approved'
|
||||
AND UPPER(p.name_en) = 'DOCTOR'
|
||||
AND ? BETWEEN lr.start_date AND lr.end_date
|
||||
");
|
||||
$stmt->execute([$date]);
|
||||
$holidays_on_date = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
@ -52,7 +56,7 @@ $query = "
|
||||
d.name_$lang as doctor_name
|
||||
FROM appointments a
|
||||
JOIN patients p ON a.patient_id = p.id
|
||||
JOIN doctors d ON a.doctor_id = d.id
|
||||
LEFT JOIN employees d ON a.doctor_id = d.id
|
||||
WHERE DATE(a.start_time) = ?
|
||||
";
|
||||
$params = [$date];
|
||||
@ -137,7 +141,7 @@ $appointments = $stmt->fetchAll();
|
||||
<?php if (!$doctor_id): ?>
|
||||
<th width="20%"><?php echo __('doctor'); ?></th>
|
||||
<?php endif; ?>
|
||||
<th><?php echo __('reason'); ?> / <?php echo __('notes'); ?></th>
|
||||
<th width="25%"><?php echo __('reason'); ?> / <?php echo __('notes'); ?></th>
|
||||
<th width="10%"><?php echo __('status'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -152,19 +156,14 @@ $appointments = $stmt->fetchAll();
|
||||
<?php endif; ?>
|
||||
<td><?php echo htmlspecialchars($app['reason'] ?: '-'); ?></td>
|
||||
<td>
|
||||
<span class="badge bg-<?php
|
||||
echo match($app['status']) {
|
||||
'Completed' => 'success',
|
||||
'Cancelled' => 'danger',
|
||||
default => 'primary'
|
||||
};
|
||||
?> text-dark bg-opacity-10 border border-<?php
|
||||
echo match($app['status']) {
|
||||
'Completed' => 'success',
|
||||
'Cancelled' => 'danger',
|
||||
default => 'primary'
|
||||
};
|
||||
?>">
|
||||
<?php
|
||||
$statusClass = match($app['status']) {
|
||||
'Completed' => 'success',
|
||||
'Cancelled' => 'danger',
|
||||
default => 'primary'
|
||||
};
|
||||
?>
|
||||
<span class="badge bg-<?php echo $statusClass; ?> text-dark bg-opacity-10 border border-<?php echo $statusClass; ?>">
|
||||
<?php echo $app['status']; ?>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
@ -28,17 +28,18 @@ try {
|
||||
}
|
||||
|
||||
// Fetch Visit and Patient Details
|
||||
// Updated to join employees instead of doctors
|
||||
$stmt = $db->prepare("
|
||||
SELECT
|
||||
v.*,
|
||||
p.name as patient_name,
|
||||
p.phone as patient_phone,
|
||||
p.civil_id,
|
||||
d.name_en as doctor_name_en,
|
||||
d.name_ar as doctor_name_ar
|
||||
e.name_en as doctor_name_en,
|
||||
e.name_ar as doctor_name_ar
|
||||
FROM visits v
|
||||
JOIN patients p ON v.patient_id = p.id
|
||||
LEFT JOIN doctors d ON v.doctor_id = d.id
|
||||
LEFT JOIN employees e ON v.doctor_id = e.id
|
||||
WHERE v.id = ?
|
||||
");
|
||||
$stmt->execute([$bill['visit_id']]);
|
||||
|
||||
@ -21,19 +21,21 @@ try {
|
||||
// Fetch visit details
|
||||
// Ensure all joined columns exist or use COALESCE/Check schema
|
||||
// We select specific columns to avoid 'ambiguous column' errors or fetching too much
|
||||
// Updated to join employees instead of doctors
|
||||
$stmt = $db->prepare("
|
||||
SELECT
|
||||
v.*,
|
||||
p.name as patient_name,
|
||||
p.dob,
|
||||
p.gender,
|
||||
d.name_en as doctor_name_en,
|
||||
d.name_ar as doctor_name_ar,
|
||||
d.specialization_en,
|
||||
d.specialization_ar
|
||||
e.name_en as doctor_name_en,
|
||||
e.name_ar as doctor_name_ar,
|
||||
dept.name_en as specialization_en,
|
||||
dept.name_ar as specialization_ar
|
||||
FROM visits v
|
||||
JOIN patients p ON v.patient_id = p.id
|
||||
JOIN doctors d ON v.doctor_id = d.id
|
||||
LEFT JOIN employees e ON v.doctor_id = e.id
|
||||
LEFT JOIN departments dept ON e.department_id = dept.id
|
||||
WHERE v.id = ?
|
||||
");
|
||||
$stmt->execute([$visit_id]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user