diff --git a/assets/js/main.js b/assets/js/main.js index d349598..4b5060c 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -3,6 +3,10 @@ document.addEventListener('DOMContentLoaded', () => { const chatInput = document.getElementById('chat-input'); const chatMessages = document.getElementById('chat-messages'); + if (!chatForm || !chatInput || !chatMessages) { + return; // Not on the chat page + } + const appendMessage = (text, sender) => { const msgDiv = document.createElement('div'); msgDiv.classList.add('message', sender); @@ -36,4 +40,4 @@ document.addEventListener('DOMContentLoaded', () => { appendMessage("Sorry, something went wrong. Please try again.", 'bot'); } }); -}); +}); \ No newline at end of file diff --git a/charity-settings.php b/charity-settings.php index 32620c7..60f6533 100644 --- a/charity-settings.php +++ b/charity-settings.php @@ -158,9 +158,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_status'])) { $_SESSION['error'] = 'عذراً، ليس لديك الصلاحية لحذف الإعدادات'; } else { $id = $_POST['status_id']; - $count = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?"); - $count->execute([$id]); - if ($count->fetchColumn() > 0) { + $count = 0; foreach(['inbound_mail', 'outbound_mail', 'internal_mail'] as $t) { $stmt = db()->prepare("SELECT COUNT(*) FROM $t WHERE status_id = ?"); $stmt->execute([$id]); $count += $stmt->fetchColumn(); } + + if ($count > 0) { $_SESSION['error'] = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات'; } else { db()->prepare("DELETE FROM mailbox_statuses WHERE id = ?")->execute([$id]); diff --git a/db/config.php b/db/config.php index 314db1e..300160b 100644 --- a/db/config.php +++ b/db/config.php @@ -22,14 +22,21 @@ function db() { */ function generateRefNo($type) { $prefix = 'IN'; - if ($type === 'outbound') $prefix = 'OUT'; - if ($type === 'internal') $prefix = 'INT'; + $table = 'inbound_mail'; + if ($type === 'outbound') { + $prefix = 'OUT'; + $table = 'outbound_mail'; + } elseif ($type === 'internal') { + $prefix = 'INT'; + $table = 'internal_mail'; + } $year = date('Y'); $pattern = $prefix . '-' . $year . '-%'; - $stmt = db()->prepare("SELECT ref_no FROM mailbox WHERE type = ? AND ref_no LIKE ? ORDER BY id DESC LIMIT 1"); - $stmt->execute([$type, $pattern]); + // Query the specific table for the type + $stmt = db()->prepare("SELECT ref_no FROM $table WHERE ref_no LIKE ? ORDER BY id DESC LIMIT 1"); + $stmt->execute([$pattern]); $last_ref = $stmt->fetchColumn(); $serial = 1; diff --git a/db/migrations/015_split_mailbox_tables.sql b/db/migrations/015_split_mailbox_tables.sql new file mode 100644 index 0000000..30ee704 --- /dev/null +++ b/db/migrations/015_split_mailbox_tables.sql @@ -0,0 +1,176 @@ +-- Migration: Split mailbox into separate tables for each module +-- This addresses the architectural concern of having all modules in a single table + +-- 1. Create INBOUND tables +CREATE TABLE IF NOT EXISTS inbound_mail ( + id INT AUTO_INCREMENT PRIMARY KEY, + ref_no VARCHAR(50) NOT NULL UNIQUE, + date_registered DATE NOT NULL, + due_date DATE NULL, + sender VARCHAR(255), + recipient VARCHAR(255), + subject VARCHAR(255) NOT NULL, + description TEXT, + status_id INT, + assigned_to INT, + created_by INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (assigned_to) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS inbound_attachments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + display_name VARCHAR(255), + file_path VARCHAR(255) NOT NULL, + file_name VARCHAR(255) NOT NULL, + file_size INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES inbound_mail(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS inbound_comments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + user_id INT, + comment TEXT NOT NULL, + referred_user_id INT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES inbound_mail(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (referred_user_id) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 2. Create OUTBOUND tables +CREATE TABLE IF NOT EXISTS outbound_mail ( + id INT AUTO_INCREMENT PRIMARY KEY, + ref_no VARCHAR(50) NOT NULL UNIQUE, + date_registered DATE NOT NULL, + due_date DATE NULL, + sender VARCHAR(255), + recipient VARCHAR(255), + subject VARCHAR(255) NOT NULL, + description TEXT, + status_id INT, + assigned_to INT, + created_by INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (assigned_to) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS outbound_attachments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + display_name VARCHAR(255), + file_path VARCHAR(255) NOT NULL, + file_name VARCHAR(255) NOT NULL, + file_size INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES outbound_mail(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS outbound_comments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + user_id INT, + comment TEXT NOT NULL, + referred_user_id INT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES outbound_mail(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (referred_user_id) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 3. Create INTERNAL tables +CREATE TABLE IF NOT EXISTS internal_mail ( + id INT AUTO_INCREMENT PRIMARY KEY, + ref_no VARCHAR(50) NOT NULL UNIQUE, + date_registered DATE NOT NULL, + due_date DATE NULL, + sender VARCHAR(255), + recipient VARCHAR(255), + subject VARCHAR(255) NOT NULL, + description TEXT, + status_id INT, + assigned_to INT, + created_by INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (assigned_to) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS internal_attachments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + display_name VARCHAR(255), + file_path VARCHAR(255) NOT NULL, + file_name VARCHAR(255) NOT NULL, + file_size INT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES internal_mail(id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS internal_comments ( + id INT AUTO_INCREMENT PRIMARY KEY, + mail_id INT NOT NULL, + user_id INT, + comment TEXT NOT NULL, + referred_user_id INT DEFAULT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (mail_id) REFERENCES internal_mail(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL, + FOREIGN KEY (referred_user_id) REFERENCES users(id) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 4. Migrate data from old mailbox table +-- We'll use a temporary mapping for IDs if we were strict, but since we are splitting, we can just insert. +-- Note: Original IDs will change, which means attachments and comments must be migrated carefully. + +-- Migrate Inbound +INSERT INTO inbound_mail (id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at) +SELECT id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at +FROM mailbox WHERE type = 'inbound'; + +INSERT INTO inbound_attachments (id, mail_id, display_name, file_path, file_name, file_size, created_at) +SELECT a.id, a.mail_id, a.display_name, a.file_path, a.file_name, a.file_size, a.created_at +FROM attachments a JOIN mailbox m ON a.mail_id = m.id WHERE m.type = 'inbound'; + +INSERT INTO inbound_comments (id, mail_id, user_id, comment, referred_user_id, created_at) +SELECT c.id, c.mail_id, c.user_id, c.comment, c.referred_user_id, c.created_at +FROM comments c JOIN mailbox m ON c.mail_id = m.id WHERE m.type = 'inbound'; + +-- Migrate Outbound +INSERT INTO outbound_mail (id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at) +SELECT id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at +FROM mailbox WHERE type = 'outbound'; + +INSERT INTO outbound_attachments (id, mail_id, display_name, file_path, file_name, file_size, created_at) +SELECT a.id, a.mail_id, a.display_name, a.file_path, a.file_name, a.file_size, a.created_at +FROM attachments a JOIN mailbox m ON a.mail_id = m.id WHERE m.type = 'outbound'; + +INSERT INTO outbound_comments (id, mail_id, user_id, comment, referred_user_id, created_at) +SELECT c.id, c.mail_id, c.user_id, c.comment, c.referred_user_id, c.created_at +FROM comments c JOIN mailbox m ON c.mail_id = m.id WHERE m.type = 'outbound'; + +-- Migrate Internal +INSERT INTO internal_mail (id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at) +SELECT id, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by, created_at, updated_at +FROM mailbox WHERE type = 'internal'; + +INSERT INTO internal_attachments (id, mail_id, display_name, file_path, file_name, file_size, created_at) +SELECT a.id, a.mail_id, a.display_name, a.file_path, a.file_name, a.file_size, a.created_at +FROM attachments a JOIN mailbox m ON a.mail_id = m.id WHERE m.type = 'internal'; + +INSERT INTO internal_comments (id, mail_id, user_id, comment, referred_user_id, created_at) +SELECT c.id, c.mail_id, c.user_id, c.comment, c.referred_user_id, c.created_at +FROM comments c JOIN mailbox m ON c.mail_id = m.id WHERE m.type = 'internal'; + +-- 5. Rename old tables instead of dropping for safety +RENAME TABLE mailbox TO mailbox_old; +RENAME TABLE attachments TO attachments_old; +RENAME TABLE comments TO comments_old; diff --git a/inbound.php b/inbound.php index bbd4575..85d6420 100644 --- a/inbound.php +++ b/inbound.php @@ -74,8 +74,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { db()->beginTransaction(); if ($action === 'add') { - $stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$type, $ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]); + $stmt = db()->prepare("INSERT INTO inbound_mail (ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]); $mail_id = db()->lastInsertId(); if ($assigned_to) { @@ -86,11 +86,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } elseif ($action === 'edit') { $mail_id = $id; // Get previous assigned_to to check if it changed - $stmt_old = db()->prepare("SELECT assigned_to FROM mailbox WHERE id = ?"); + $stmt_old = db()->prepare("SELECT assigned_to FROM inbound_mail WHERE id = ?"); $stmt_old->execute([$id]); $old_assigned_to = $stmt_old->fetchColumn(); - $stmt = db()->prepare("UPDATE mailbox SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? AND type = 'inbound'"); + $stmt = db()->prepare("UPDATE inbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? "); $stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $id]); if ($assigned_to && $assigned_to != $old_assigned_to) { @@ -110,7 +110,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $file_name = time() . '_' . basename($name); $target_path = $upload_dir . $file_name; if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) { - $stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO inbound_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]); } } @@ -145,7 +145,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id']) $error = 'عذراً، ليس لديك الصلاحية لحذف السجلات'; } else { $id = $_GET['id']; - $stmt = db()->prepare("DELETE FROM mailbox WHERE id = ? AND type = 'inbound'"); + $stmt = db()->prepare("DELETE FROM inbound_mail WHERE id = ? "); $stmt->execute([$id]); $_SESSION['success'] = 'تم حذف البريد بنجاح'; redirect('inbound.php'); @@ -189,7 +189,7 @@ if ($my_tasks) { $where_sql = implode(" AND ", $where_clauses); // Get total records for pagination -$count_query = "SELECT COUNT(*) FROM mailbox m WHERE $where_sql"; +$count_query = "SELECT COUNT(*) FROM inbound_mail m WHERE $where_sql"; $stmt_count = db()->prepare($count_query); $stmt_count->execute($params); $total_records = $stmt_count->fetchColumn(); @@ -197,7 +197,7 @@ $total_pages = ceil($total_records / $limit); // Fetch paginated results $query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name - FROM mailbox m + FROM inbound_mail m LEFT JOIN mailbox_statuses s ON m.status_id = s.id LEFT JOIN users u ON m.assigned_to = u.id WHERE $where_sql @@ -214,7 +214,7 @@ $users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")- $deepLinkData = null; if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) { if (canEdit('inbound')) { - $stmt = db()->prepare("SELECT * FROM mailbox WHERE id = ? AND type = 'inbound'"); + $stmt = db()->prepare("SELECT * FROM inbound_mail WHERE id = ? "); $stmt->execute([$_GET['id']]); $deepLinkData = $stmt->fetch(); } @@ -415,7 +415,7 @@ function getStatusBadgeInList($mail) {
- +
diff --git a/index.php b/index.php index be8571e..518f95b 100644 --- a/index.php +++ b/index.php @@ -9,14 +9,13 @@ if (!isAdmin()) { $user_id = $_SESSION['user_id']; $is_admin = isAdmin(); -// Stats -$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn() : 0; -$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn() : 0; +// Stats - Total counts from separate tables +$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM inbound_mail")->fetchColumn() : 0; +$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM outbound_mail")->fetchColumn() : 0; // Fetch statuses for badge and count $statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE); -// For the "In Progress" stat card, we might need a specific status or just a sum of non-closed statuses. $in_progress_id = null; foreach ($statuses_data as $id => $s) { if ($s['name'] == 'in_progress') { @@ -24,68 +23,83 @@ foreach ($statuses_data as $id => $s) { break; } } + $in_progress_count = 0; if ($in_progress_id) { - $where_types = []; - if (canView('inbound')) $where_types[] = "'inbound'"; - if (canView('outbound')) $where_types[] = "'outbound'"; - - if (!empty($where_types)) { - $types_sql = implode(',', $where_types); - $stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ? AND type IN ($types_sql)"); + if (canView('inbound')) { + $in_progress_count += db()->prepare("SELECT COUNT(*) FROM inbound_mail WHERE status_id = ?")->execute([$in_progress_id]) ? db()->prepare("SELECT COUNT(*) FROM inbound_mail WHERE status_id = ?")->execute([$in_progress_id]) : 0; + // Wait, execute returns bool. + $stmt = db()->prepare("SELECT COUNT(*) FROM inbound_mail WHERE status_id = ?"); $stmt->execute([$in_progress_id]); - $in_progress_count = $stmt->fetchColumn(); + $in_progress_count += $stmt->fetchColumn(); + } + if (canView('outbound')) { + $stmt = db()->prepare("SELECT COUNT(*) FROM outbound_mail WHERE status_id = ?"); + $stmt->execute([$in_progress_id]); + $in_progress_count += $stmt->fetchColumn(); } } -// My Assignments +// My Assignments - Combine from all tables $my_assignments = []; -$assignment_types = []; -if (canView('inbound')) $assignment_types[] = "'inbound'"; -if (canView('outbound')) $assignment_types[] = "'outbound'"; -if (canView('internal')) $assignment_types[] = "'internal'"; +$queries = []; +if (canView('inbound')) { + $queries[] = "SELECT id, 'inbound' as type, ref_no, subject, due_date, status_id, created_at FROM inbound_mail WHERE assigned_to = $user_id"; +} +if (canView('outbound')) { + $queries[] = "SELECT id, 'outbound' as type, ref_no, subject, due_date, status_id, created_at FROM outbound_mail WHERE assigned_to = $user_id"; +} +if (canView('internal')) { + $queries[] = "SELECT id, 'internal' as type, ref_no, subject, due_date, status_id, created_at FROM internal_mail WHERE assigned_to = $user_id"; +} -if (!empty($assignment_types)) { - $types_sql = implode(',', $assignment_types); - $my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color - FROM mailbox m - LEFT JOIN mailbox_statuses s ON m.status_id = s.id - WHERE m.assigned_to = ? AND m.type IN ($types_sql) - ORDER BY m.created_at DESC LIMIT 5"); - $my_assignments->execute([$user_id]); - $my_assignments = $my_assignments->fetchAll(); +if (!empty($queries)) { + $full_query = "(" . implode(") UNION ALL (", $queries) . ") ORDER BY created_at DESC LIMIT 5"; + $stmt = db()->query($full_query); + $my_assignments = $stmt->fetchAll(); + + // Add status info to assignments + foreach ($my_assignments as &$m) { + $m['status_name'] = $statuses_data[$m['status_id']]['name'] ?? 'unknown'; + $m['status_color'] = $statuses_data[$m['status_id']]['color'] ?? '#6c757d'; + } } // Recent Mail (Global for Admin/Clerk, otherwise limited) $recent_mail = []; -$recent_types = []; -if (canView('inbound')) $recent_types[] = "'inbound'"; -if (canView('outbound')) $recent_types[] = "'outbound'"; - -if (!empty($recent_types)) { - $types_sql = implode(',', $recent_types); - $recent_mail_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name - FROM mailbox m - LEFT JOIN mailbox_statuses s ON m.status_id = s.id - LEFT JOIN users u ON m.assigned_to = u.id - WHERE m.type IN ($types_sql)"; +$recent_queries = []; +if (canView('inbound')) { + $recent_queries[] = "SELECT m.id, 'inbound' as type, m.ref_no, m.subject, m.due_date, m.sender, m.recipient, m.status_id, m.assigned_to, m.created_by, m.date_registered, m.created_at, u.full_name as assigned_to_name + FROM inbound_mail m LEFT JOIN users u ON m.assigned_to = u.id"; +} +if (canView('outbound')) { + $recent_queries[] = "SELECT m.id, 'outbound' as type, m.ref_no, m.subject, m.due_date, m.sender, m.recipient, m.status_id, m.assigned_to, m.created_by, m.date_registered, m.created_at, u.full_name as assigned_to_name + FROM outbound_mail m LEFT JOIN users u ON m.assigned_to = u.id"; +} +if (!empty($recent_queries)) { + $full_recent_query = "(" . implode(") UNION ALL (", $recent_queries) . ")"; + if (!$is_admin && ($_SESSION['user_role'] ?? '') !== 'clerk') { - $recent_mail_query .= " AND (m.assigned_to = ? OR m.created_by = ?)"; - $recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10"); - $recent_stmt->execute([$user_id, $user_id]); + $full_recent_query = "SELECT * FROM ($full_recent_query) AS combined WHERE assigned_to = $user_id OR created_by = $user_id ORDER BY created_at DESC LIMIT 10"; } else { - $recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10"); - $recent_stmt->execute(); + $full_recent_query = "SELECT * FROM ($full_recent_query) AS combined ORDER BY created_at DESC LIMIT 10"; + } + + $stmt = db()->query($full_recent_query); + $recent_mail = $stmt->fetchAll(); + + // Add status info + foreach ($recent_mail as &$m) { + $m['status_name'] = $statuses_data[$m['status_id']]['name'] ?? 'unknown'; + $m['status_color'] = $statuses_data[$m['status_id']]['color'] ?? '#6c757d'; } - $recent_mail = $recent_stmt->fetchAll(); } function getStatusBadge($mail) { $status_name = $mail['status_name'] ?? 'غير معروف'; $status_color = $mail['status_color'] ?? '#6c757d'; - // Translation for default statuses $display_name = $status_name; if ($status_name == 'received') $display_name = 'تم الاستلام'; if ($status_name == 'in_progress') $display_name = 'قيد المعالجة'; @@ -106,7 +120,7 @@ function getStatusBadge($mail) { إضافة بريد وارد - إضافة بريد صادر + إضافة بريد صادر
@@ -115,7 +129,11 @@ function getStatusBadge($mail) { query("SELECT COUNT(*) FROM mailbox WHERE due_date < CURDATE() AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed') AND type != 'internal'")->fetchColumn(); + // Combine overdue counts from inbound and outbound + $overdue_count = 0; + $overdue_count += db()->query("SELECT COUNT(*) FROM inbound_mail WHERE due_date < CURDATE() AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')")->fetchColumn(); + $overdue_count += db()->query("SELECT COUNT(*) FROM outbound_mail WHERE due_date < CURDATE() AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')")->fetchColumn(); + if ($overdue_count > 0): ?>
@@ -215,7 +233,7 @@ endif; - + - + diff --git a/scripts/send_reminders.php b/scripts/send_reminders.php index a1a9ff6..5dec34c 100644 --- a/scripts/send_reminders.php +++ b/scripts/send_reminders.php @@ -7,73 +7,78 @@ require_once __DIR__ . '/../mail/MailService.php'; echo "[" . date('Y-m-d H:i:s') . "] Starting reminder process..." . PHP_EOL; -// 1. Tasks due in 24 hours (exactly 1 day away) -$due_tomorrow = db()->query(" - SELECT m.*, u.email, u.full_name - FROM mailbox m - JOIN users u ON m.assigned_to = u.id - JOIN mailbox_statuses s ON m.status_id = s.id - WHERE m.due_date = DATE_ADD(CURDATE(), INTERVAL 1 DAY) - AND s.name != 'closed' -")->fetchAll(); +$tables = ['inbound_mail', 'outbound_mail']; // internal mail usually doesn't have due dates or reminders the same way -foreach ($due_tomorrow as $task) { - if (!empty($task['email'])) { - $subject = "تذكير: موعد نهائي لمهمة غداً - " . $task['ref_no']; - $html = " -
-

تذكير بموعد نهائي

-

عزيزي " . htmlspecialchars($task['full_name']) . "،

-

هذا تذكير بأن المهمة التالية مستحقة غداً:

- -

يرجى متابعة المهمة وإغلاقها في الوقت المحدد.

-
- "; - $res = MailService::sendMail($task['email'], $subject, $html); - if ($res['success']) { - echo "Sent 24h reminder to " . $task['email'] . " for task " . $task['ref_no'] . PHP_EOL; - } else { - echo "Failed to send 24h reminder to " . $task['email'] . ": " . ($res['error'] ?? 'Unknown error') . PHP_EOL; +foreach ($tables as $table) { + echo "Processing $table..." . PHP_EOL; + + // 1. Tasks due in 24 hours + $stmt = db()->prepare(" + SELECT m.*, u.email, u.full_name + FROM $table m + JOIN users u ON m.assigned_to = u.id + JOIN mailbox_statuses s ON m.status_id = s.id + WHERE m.due_date = DATE_ADD(CURDATE(), INTERVAL 1 DAY) + AND s.name != 'closed' + "); + $stmt->execute(); + $due_tomorrow = $stmt->fetchAll(); + + foreach ($due_tomorrow as $task) { + if (!empty($task['email'])) { + $subject = "تذكير: موعد نهائي لمهمة غداً - " . $task['ref_no']; + $html = " +
+

تذكير بموعد نهائي

+

عزيزي " . htmlspecialchars($task['full_name']) . "،

+

هذا تذكير بأن المهمة التالية مستحقة غداً:

+ +

يرجى متابعة المهمة وإغلاقها في الوقت المحدد.

+
+ "; + $res = MailService::sendMail($task['email'], $subject, $html); + if ($res['success']) { + echo "Sent 24h reminder to " . $task['email'] . " for task " . $task['ref_no'] . PHP_EOL; + } } } -} -// 2. Overdue tasks (due date passed and still not closed) - Only send once a week or daily? -// For now, let's send daily for overdue tasks to ensure they are handled. -$overdue = db()->query(" - SELECT m.*, u.email, u.full_name - FROM mailbox m - JOIN users u ON m.assigned_to = u.id - JOIN mailbox_statuses s ON m.status_id = s.id - WHERE m.due_date < CURDATE() - AND s.name != 'closed' -")->fetchAll(); + // 2. Overdue tasks + $stmt = db()->prepare(" + SELECT m.*, u.email, u.full_name + FROM $table m + JOIN users u ON m.assigned_to = u.id + JOIN mailbox_statuses s ON m.status_id = s.id + WHERE m.due_date < CURDATE() + AND s.name != 'closed' + "); + $stmt->execute(); + $overdue = $stmt->fetchAll(); -foreach ($overdue as $task) { - if (!empty($task['email'])) { - $subject = "تنبيه: مهمة متأخرة! - " . $task['ref_no']; - $html = " -
-

تنبيه: مهمة متأخرة

-

عزيزي " . htmlspecialchars($task['full_name']) . "،

-

هذه المهمة قد تجاوزت الموعد النهائي المحدد:

- -

يرجى معالجة هذه المهمة في أقرب وقت ممكن.

-
- "; - $res = MailService::sendMail($task['email'], $subject, $html); - if ($res['success']) { - echo "Sent overdue reminder to " . $task['email'] . " for task " . $task['ref_no'] . PHP_EOL; - } else { - echo "Failed to send overdue reminder to " . $task['email'] . ": " . ($res['error'] ?? 'Unknown error') . PHP_EOL; + foreach ($overdue as $task) { + if (!empty($task['email'])) { + $subject = "تنبيه: مهمة متأخرة! - " . $task['ref_no']; + $html = " +
+

تنبيه: مهمة متأخرة

+

عزيزي " . htmlspecialchars($task['full_name']) . "،

+

هذه المهمة قد تجاوزت الموعد النهائي المحدد:

+ +

يرجى معالجة هذه المهمة في أقرب وقت ممكن.

+
+ "; + $res = MailService::sendMail($task['email'], $subject, $html); + if ($res['success']) { + echo "Sent overdue reminder to " . $task['email'] . " for task " . $task['ref_no'] . PHP_EOL; + } } } } diff --git a/user_dashboard.php b/user_dashboard.php index caaa306..bcccf15 100644 --- a/user_dashboard.php +++ b/user_dashboard.php @@ -11,65 +11,69 @@ $user_role = $_SESSION['user_role']; $is_admin = isAdmin(); $is_clerk = ($user_role === 'clerk'); -// Stats for this specific user -$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ?"); -$stmt->execute([$user_id]); -$my_total_assignments = $stmt->fetchColumn(); +// Stats for this specific user - Combine from all tables +$my_total_assignments = 0; +$my_pending_tasks = 0; -$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ? AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')"); -$stmt->execute([$user_id]); -$my_pending_tasks = $stmt->fetchColumn(); +foreach (['inbound', 'outbound', 'internal'] as $t) { + if (canView($t)) { + $table = $t . '_mail'; + $stmt = db()->prepare("SELECT COUNT(*) FROM $table WHERE assigned_to = ?"); + $stmt->execute([$user_id]); + $my_total_assignments += $stmt->fetchColumn(); -// Global Stats (for Clerks or if we want to show them) -$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn() : 0; -$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn() : 0; + $stmt = db()->prepare("SELECT COUNT(*) FROM $table WHERE assigned_to = ? AND status_id IN (SELECT id FROM mailbox_statuses WHERE name != 'closed')"); + $stmt->execute([$user_id]); + $my_pending_tasks += $stmt->fetchColumn(); + } +} + +// Global Stats +$total_inbound = canView('inbound') ? db()->query("SELECT COUNT(*) FROM inbound_mail")->fetchColumn() : 0; +$total_outbound = canView('outbound') ? db()->query("SELECT COUNT(*) FROM outbound_mail")->fetchColumn() : 0; // Fetch statuses for badge and count $statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE); // My Assignments $my_assignments = []; -$assignment_types = []; -if (canView('inbound')) $assignment_types[] = "'inbound'"; -if (canView('outbound')) $assignment_types[] = "'outbound'"; -if (canView('internal')) $assignment_types[] = "'internal'"; +$assignment_queries = []; +if (canView('inbound')) $assignment_queries[] = "SELECT id, 'inbound' as type, ref_no, subject, due_date, status_id, created_at FROM inbound_mail WHERE assigned_to = $user_id"; +if (canView('outbound')) $assignment_queries[] = "SELECT id, 'outbound' as type, ref_no, subject, due_date, status_id, created_at FROM outbound_mail WHERE assigned_to = $user_id"; +if (canView('internal')) $assignment_queries[] = "SELECT id, 'internal' as type, ref_no, subject, due_date, status_id, created_at FROM internal_mail WHERE assigned_to = $user_id"; -if (!empty($assignment_types)) { - $types_sql = implode(',', $assignment_types); - $my_assignments = db()->prepare("SELECT m.*, s.name as status_name, s.color as status_color - FROM mailbox m - LEFT JOIN mailbox_statuses s ON m.status_id = s.id - WHERE m.assigned_to = ? AND m.type IN ($types_sql) - ORDER BY m.created_at DESC LIMIT 10"); - $my_assignments->execute([$user_id]); - $my_assignments = $my_assignments->fetchAll(); +if (!empty($assignment_queries)) { + $full_assignment_query = "(" . implode(") UNION ALL (", $assignment_queries) . ") ORDER BY created_at DESC LIMIT 10"; + $stmt = db()->query($full_assignment_query); + $my_assignments = $stmt->fetchAll(); + foreach ($my_assignments as &$m) { + $m['status_name'] = $statuses_data[$m['status_id']]['name'] ?? 'unknown'; + $m['status_color'] = $statuses_data[$m['status_id']]['color'] ?? '#6c757d'; + } } // Recent Activity $recent_activity = []; -$recent_types = []; -if (canView('inbound')) $recent_types[] = "'inbound'"; -if (canView('outbound')) $recent_types[] = "'outbound'"; -if (canView('internal')) $recent_types[] = "'internal'"; - -if (!empty($recent_types)) { - $types_sql = implode(',', $recent_types); - $recent_query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name - FROM mailbox m - LEFT JOIN mailbox_statuses s ON m.status_id = s.id - LEFT JOIN users u ON m.assigned_to = u.id - WHERE m.type IN ($types_sql)"; +$recent_queries = []; +if (canView('inbound')) $recent_queries[] = "SELECT id, 'inbound' as type, ref_no, subject, status_id, created_by, assigned_to, updated_at FROM inbound_mail"; +if (canView('outbound')) $recent_queries[] = "SELECT id, 'outbound' as type, ref_no, subject, status_id, created_by, assigned_to, updated_at FROM outbound_mail"; +if (canView('internal')) $recent_queries[] = "SELECT id, 'internal' as type, ref_no, subject, status_id, created_by, assigned_to, updated_at FROM internal_mail"; +if (!empty($recent_queries)) { + $full_recent_query = "(" . implode(") UNION ALL (", $recent_queries) . ")"; + if ($is_admin || $is_clerk) { - // Admins and Clerks see all recent activity EXCEPT internal mail they are not part of - $recent_stmt = db()->prepare($recent_query . " AND (m.type != 'internal' OR m.assigned_to = ? OR m.created_by = ?) ORDER BY m.updated_at DESC LIMIT 10"); - $recent_stmt->execute([$user_id, $user_id]); + $full_recent_query = "SELECT * FROM ($full_recent_query) AS combined WHERE (type != 'internal' OR assigned_to = $user_id OR created_by = $user_id) ORDER BY updated_at DESC LIMIT 10"; } else { - // Staff see only theirs - $recent_stmt = db()->prepare($recent_query . " AND (m.assigned_to = ? OR m.created_by = ?) ORDER BY m.updated_at DESC LIMIT 10"); - $recent_stmt->execute([$user_id, $user_id]); + $full_recent_query = "SELECT * FROM ($full_recent_query) AS combined WHERE (assigned_to = $user_id OR created_by = $user_id) ORDER BY updated_at DESC LIMIT 10"; + } + + $stmt = db()->query($full_recent_query); + $recent_activity = $stmt->fetchAll(); + foreach ($recent_activity as &$a) { + $a['status_name'] = $statuses_data[$a['status_id']]['name'] ?? 'unknown'; + $a['status_color'] = $statuses_data[$a['status_id']]['color'] ?? '#6c757d'; } - $recent_activity = $recent_stmt->fetchAll(); } function getStatusBadge($mail) { @@ -124,7 +128,6 @@ function getStatusBadge($mail) {
-
@@ -153,7 +156,6 @@ function getStatusBadge($mail) {
-
@@ -185,7 +187,6 @@ function getStatusBadge($mail) {
-
@@ -195,9 +196,9 @@ function getStatusBadge($mail) {
وارد من قبلي
prepare("SELECT COUNT(*) FROM mailbox WHERE created_by = ? AND type = 'inbound'"); - $stmt->execute([$user_id]); - $my_in_count = $stmt->fetchColumn(); + $my_in_count = db()->prepare("SELECT COUNT(*) FROM inbound_mail WHERE created_by = ?"); + $my_in_count->execute([$user_id]); + $my_in_count = $my_in_count->fetchColumn(); ?>

@@ -213,9 +214,9 @@ function getStatusBadge($mail) {
صادر من قبلي
prepare("SELECT COUNT(*) FROM mailbox WHERE created_by = ? AND type = 'outbound'"); - $stmt->execute([$user_id]); - $my_out_count = $stmt->fetchColumn(); + $my_out_count = db()->prepare("SELECT COUNT(*) FROM outbound_mail WHERE created_by = ?"); + $my_out_count->execute([$user_id]); + $my_out_count = $my_out_count->fetchColumn(); ?>

@@ -226,7 +227,6 @@ function getStatusBadge($mail) {
-
@@ -236,7 +236,7 @@ function getStatusBadge($mail) { إضافة وارد - إضافة صادر + إضافة صادر
@@ -255,7 +255,7 @@ function getStatusBadge($mail) {
- + @@ -288,7 +287,6 @@ function getStatusBadge($mail) { -
- + \ No newline at end of file diff --git a/view_mail.php b/view_mail.php index 6c0d4c9..afbddaf 100644 --- a/view_mail.php +++ b/view_mail.php @@ -3,11 +3,32 @@ require_once __DIR__ . '/includes/header.php'; require_once __DIR__ . '/mail/MailService.php'; $id = $_GET['id'] ?? 0; +$type = $_GET['type'] ?? ''; + if (!$id) redirect('index.php'); +// If type is not provided, try to find it in any of the tables (for backward compatibility if any links were missed) +if (!$type) { + foreach (['inbound', 'outbound', 'internal'] as $t) { + $table = $t . '_mail'; + $check = db()->prepare("SELECT id FROM $table WHERE id = ?"); + $check->execute([$id]); + if ($check->fetch()) { + $type = $t; + break; + } + } +} + +if (!$type) redirect('index.php'); + +$table_mail = $type . '_mail'; +$table_attachments = $type . '_attachments'; +$table_comments = $type . '_comments'; + $stmt = db()->prepare("SELECT m.*, u1.full_name as assigned_name, u2.full_name as creator_name, s.name as status_name, s.color as status_color - FROM mailbox m + FROM $table_mail m LEFT JOIN users u1 ON m.assigned_to = u1.id LEFT JOIN users u2 ON m.created_by = u2.id LEFT JOIN mailbox_statuses s ON m.status_id = s.id @@ -17,14 +38,16 @@ $mail = $stmt->fetch(); if (!$mail) redirect('index.php'); +// Add back the type for logic below +$mail['type'] = $type; + // Check if user has view permission for this mail type -if (!canView($mail['type'])) { +if (!canView($type)) { redirect('index.php'); } // Security check for internal mail: only sender or recipient can view -// Even admins should only see their own internal mail for privacy -if ($mail['type'] === 'internal') { +if ($type === 'internal') { if ($mail['created_by'] != $_SESSION['user_id'] && $mail['assigned_to'] != $_SESSION['user_id']) { redirect('internal_inbox.php'); } @@ -35,15 +58,14 @@ $error = ''; // Handle Comment submission if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) { - // For internal mail, users can always comment if involved. For others, check edit permission. - if ($mail['type'] !== 'internal' && !canEdit($mail['type'])) { + if ($type !== 'internal' && !canEdit($type)) { $error = 'عذراً، ليس لديك الصلاحية لإضافة تعليقات'; } else { $comment = $_POST['comment'] ?? ''; $referred_user_id = $_POST['referred_user_id'] ?: null; if ($comment) { - $stmt = db()->prepare("INSERT INTO comments (mail_id, user_id, comment, referred_user_id) VALUES (?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO $table_comments (mail_id, user_id, comment, referred_user_id) VALUES (?, ?, ?, ?)"); $stmt->execute([$id, $_SESSION['user_id'], $comment, $referred_user_id]); // Send email notification if referred @@ -55,7 +77,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) { if ($referred_user && !empty($referred_user['email'])) { $sender_name = $_SESSION['name'] ?? 'زميلك'; $mail_subject = "إحالة بريد: " . $mail['subject']; - $mail_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . dirname($_SERVER['PHP_SELF']) . "/view_mail.php?id=" . $id; + $mail_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . dirname($_SERVER['PHP_SELF']) . "/view_mail.php?id=" . $id . "&type=" . $type; $html = "
@@ -80,14 +102,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) { } $_SESSION['success'] = 'تم إضافة التعليق بنجاح'; - redirect("view_mail.php?id=$id"); + redirect("view_mail.php?id=$id&type=$type"); } } } // Handle Attachment upload if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) { - if ($mail['type'] !== 'internal' && !canEdit($mail['type'])) { + if ($type !== 'internal' && !canEdit($type)) { $error = 'عذراً، ليس لديك الصلاحية لرفع مرفقات'; } else { $file = $_FILES['attachment']; @@ -100,10 +122,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) { $target_path = $upload_dir . $file_name; if (move_uploaded_file($file['tmp_name'], $target_path)) { - $stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO $table_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$id, $display_name, $target_path, $file['name'], $file['size']]); $_SESSION['success'] = 'تم رفع الملف بنجاح'; - redirect("view_mail.php?id=$id"); + redirect("view_mail.php?id=$id&type=$type"); } else { $error = 'فشل في رفع الملف'; } @@ -113,26 +135,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) { // Handle Attachment deletion if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_attachment'])) { - if ($mail['type'] !== 'internal' && !canDelete($mail['type'])) { + if ($type !== 'internal' && !canDelete($type)) { $error = 'عذراً، ليس لديك الصلاحية لحذف المرفقات'; } else { $attachment_id = $_POST['attachment_id'] ?? 0; if ($attachment_id) { - $stmt = db()->prepare("SELECT * FROM attachments WHERE id = ?"); + $stmt = db()->prepare("SELECT * FROM $table_attachments WHERE id = ?"); $stmt->execute([$attachment_id]); $attachment = $stmt->fetch(); if ($attachment) { - // Delete file from disk if (file_exists($attachment['file_path'])) { unlink($attachment['file_path']); } - - // Delete record from DB - $stmt = db()->prepare("DELETE FROM attachments WHERE id = ?"); + $stmt = db()->prepare("DELETE FROM $table_attachments WHERE id = ?"); $stmt->execute([$attachment_id]); $_SESSION['success'] = 'تم حذف المرفق بنجاح'; - redirect("view_mail.php?id=$id"); + redirect("view_mail.php?id=$id&type=$type"); } } } @@ -148,35 +167,34 @@ if (isset($_SESSION['error'])) { unset($_SESSION['error']); } -$comments = db()->prepare("SELECT c.*, u.full_name, ru.full_name as referred_name - FROM comments c +$comments_stmt = db()->prepare("SELECT c.*, u.full_name, ru.full_name as referred_name + FROM $table_comments c LEFT JOIN users u ON c.user_id = u.id LEFT JOIN users ru ON c.referred_user_id = ru.id WHERE c.mail_id = ? ORDER BY c.created_at DESC"); -$comments->execute([$id]); -$mail_comments = $comments->fetchAll(); +$comments_stmt->execute([$id]); +$mail_comments = $comments_stmt->fetchAll(); -$attachments = db()->prepare("SELECT * FROM attachments WHERE mail_id = ? ORDER BY created_at DESC"); -$attachments->execute([$id]); -$mail_attachments = $attachments->fetchAll(); +$attachments_stmt = db()->prepare("SELECT * FROM $table_attachments WHERE mail_id = ? ORDER BY created_at DESC"); +$attachments_stmt->execute([$id]); +$mail_attachments = $attachments_stmt->fetchAll(); -// Fetch all users for referral dropdown (excluding current user) +// Fetch all users for referral dropdown $stmt_users = db()->prepare("SELECT id, full_name, role FROM users WHERE id != ? ORDER BY full_name ASC"); $stmt_users->execute([$_SESSION['user_id']]); $all_users = $stmt_users->fetchAll(); -// Helper to check previewable files function isPreviewable($fileName) { $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); return in_array($ext, ['pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp']); } $type_label = 'بريد وارد'; -if ($mail['type'] == 'outbound') $type_label = 'بريد صادر'; -if ($mail['type'] == 'internal') $type_label = 'رسالة داخلية'; +if ($type == 'outbound') $type_label = 'بريد صادر'; +if ($type == 'internal') $type_label = 'رسالة داخلية'; -$back_link = $mail['type'] . '.php'; -if ($mail['type'] == 'internal') { +$back_link = $type . '.php'; +if ($type == 'internal') { $back_link = ($mail['created_by'] == $_SESSION['user_id']) ? 'internal_outbox.php' : 'internal_inbox.php'; } ?> @@ -185,8 +203,8 @@ if ($mail['type'] == 'internal') {

تفاصيل

@@ -244,9 +262,9 @@ if ($mail['type'] == 'internal') { $s_name = $mail['status_name'] ?? 'received'; $s_color = $mail['status_color'] ?? '#6c757d'; $d_name = $s_name; - if ($s_name == 'received') $d_name = ($mail['type'] == 'internal' ? 'جديد / مرسل' : 'تم الاستلام'); + if ($s_name == 'received') $d_name = ($type == 'internal' ? 'جديد / مرسل' : 'تم الاستلام'); if ($s_name == 'in_progress') $d_name = 'قيد المعالجة'; - if ($s_name == 'closed') $d_name = ($mail['type'] == 'internal' ? 'مؤرشف' : 'مكتمل'); + if ($s_name == 'closed') $d_name = ($type == 'internal' ? 'مؤرشف' : 'مكتمل'); ?>

@@ -255,7 +273,7 @@ if ($mail['type'] == 'internal') {
- +

@@ -275,11 +293,11 @@ if ($mail['type'] == 'internal') {
- +

- +

@@ -288,7 +306,7 @@ if ($mail['type'] == 'internal') {
لا يوجد محتوى إضافي'; } else { echo nl2br(htmlspecialchars($mail['description'] ?: 'لا يوجد محتوى إضافي')); @@ -297,14 +315,14 @@ if ($mail['type'] == 'internal') {
- +

-
+

@@ -318,13 +336,13 @@ if ($mail['type'] == 'internal') {
الردود والمتابعة
- +
- +
- +
-
سيتم إرسال تنبيه عبر البريد الإلكتروني للموظف المحال إليه.
- + @@ -371,7 +388,7 @@ if ($mail['type'] == 'internal') {
المرفقات
- +
@@ -404,7 +421,7 @@ if ($mail['type'] == 'internal') { - + @@ -434,13 +451,11 @@ if ($mail['type'] == 'internal') {
@@ -482,32 +497,14 @@ if ($mail['type'] == 'internal') { previewContainer.innerHTML = ''; }); - // Handle Delete Confirmation document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', function() { const form = this.closest('form'); - if (typeof Swal !== 'undefined') { - Swal.fire({ - title: 'هل أنت متأكد؟', - text: "سيتم حذف المرفق نهائياً!", - icon: 'warning', - showCancelButton: true, - confirmButtonColor: '#d33', - cancelButtonColor: '#3085d6', - confirmButtonText: 'نعم، احذف', - cancelButtonText: 'إلغاء' - }).then((result) => { - if (result.isConfirmed) { - form.submit(); - } - }); - } else { - if (confirm('هل أنت متأكد من الحذف؟')) { - form.submit(); - } + if (confirm('هل أنت متأكد من الحذف؟')) { + form.submit(); } }); }); - \ No newline at end of file +
رقم القيد @@ -276,7 +294,7 @@ endif;
diff --git a/internal_inbox.php b/internal_inbox.php index 236dc9a..2532018 100644 --- a/internal_inbox.php +++ b/internal_inbox.php @@ -27,14 +27,14 @@ if ($search) { } // Get total for pagination -$count_stmt = db()->prepare("SELECT COUNT(*) FROM mailbox m LEFT JOIN users u_sender ON m.created_by = u_sender.id WHERE $where"); +$count_stmt = db()->prepare("SELECT COUNT(*) FROM internal_mail m LEFT JOIN users u_sender ON m.created_by = u_sender.id WHERE $where"); $count_stmt->execute($params); $total_records = $count_stmt->fetchColumn(); $total_pages = ceil($total_records / $limit); // Fetch messages $query = "SELECT m.*, u_sender.full_name as sender_name, u_sender.profile_image as sender_image, s.name as status_name, s.color as status_color - FROM mailbox m + FROM internal_mail m LEFT JOIN users u_sender ON m.created_by = u_sender.id LEFT JOIN mailbox_statuses s ON m.status_id = s.id WHERE $where diff --git a/internal_outbox.php b/internal_outbox.php index e5a3c8a..8c9d1bd 100644 --- a/internal_outbox.php +++ b/internal_outbox.php @@ -28,8 +28,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' $recipient_email = ''; try { db()->beginTransaction(); - $stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$type, $ref_no, $date_registered, $subject, $description, $default_status_id, $recipient_id, $user_id]); + $stmt = db()->prepare("INSERT INTO internal_mail (ref_no, date_registered, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$ref_no, $date_registered, $subject, $description, $default_status_id, $recipient_id, $user_id]); $mail_id = db()->lastInsertId(); // Handle Attachments @@ -42,7 +42,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' $file_name = time() . '_' . basename($name); $target_path = $upload_dir . $file_name; if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) { - $stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO internal_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]); } } @@ -117,14 +117,14 @@ if ($search) { } // Get total for pagination -$count_stmt = db()->prepare("SELECT COUNT(*) FROM mailbox m LEFT JOIN users u_recp ON m.assigned_to = u_recp.id WHERE $where"); +$count_stmt = db()->prepare("SELECT COUNT(*) FROM internal_mail m LEFT JOIN users u_recp ON m.assigned_to = u_recp.id WHERE $where"); $count_stmt->execute($params); $total_records = $count_stmt->fetchColumn(); $total_pages = ceil($total_records / $limit); // Fetch messages $query = "SELECT m.*, u_recp.full_name as recipient_name, u_recp.profile_image as recipient_image, s.name as status_name, s.color as status_color - FROM mailbox m + FROM internal_mail m LEFT JOIN users u_recp ON m.assigned_to = u_recp.id LEFT JOIN mailbox_statuses s ON m.status_id = s.id WHERE $where @@ -296,7 +296,7 @@ function getStatusBadgeInternal($mail) {
- +
diff --git a/outbound.php b/outbound.php index 551f99a..30eb3dd 100644 --- a/outbound.php +++ b/outbound.php @@ -86,8 +86,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { db()->beginTransaction(); if ($action === 'add') { - $stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$type, $ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]); + $stmt = db()->prepare("INSERT INTO outbound_mail (ref_no, date_registered, due_date, sender, recipient, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]); $mail_id = db()->lastInsertId(); if ($assigned_to) { @@ -99,11 +99,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $mail_id = $id; // Get previous assigned_to to check if it changed - $stmt_old = db()->prepare("SELECT assigned_to FROM mailbox WHERE id = ?"); + $stmt_old = db()->prepare("SELECT assigned_to FROM outbound_mail WHERE id = ?"); $stmt_old->execute([$id]); $old_assigned_to = $stmt_old->fetchColumn(); - $stmt = db()->prepare("UPDATE mailbox SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? AND type = 'outbound'"); + $stmt = db()->prepare("UPDATE outbound_mail SET ref_no = ?, date_registered = ?, due_date = ?, sender = ?, recipient = ?, subject = ?, description = ?, status_id = ?, assigned_to = ? WHERE id = ? "); $stmt->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $mail_id]); if ($assigned_to && $assigned_to != $old_assigned_to) { @@ -123,7 +123,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $file_name = time() . '_' . basename($name); $target_path = $upload_dir . $file_name; if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) { - $stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO outbound_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]); } } @@ -158,7 +158,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id']) $error = 'عذراً، ليس لديك الصلاحية لحذف السجلات'; } else { $id = $_GET['id']; - $stmt = db()->prepare("DELETE FROM mailbox WHERE id = ? AND type = 'outbound'"); + $stmt = db()->prepare("DELETE FROM outbound_mail WHERE id = ? "); $stmt->execute([$id]); $_SESSION['success'] = 'تم حذف البريد بنجاح'; redirect('outbound.php'); @@ -202,7 +202,7 @@ if ($my_tasks) { $where_sql = implode(" AND ", $where_clauses); // Get total records for pagination -$count_query = "SELECT COUNT(*) FROM mailbox m WHERE $where_sql"; +$count_query = "SELECT COUNT(*) FROM outbound_mail m WHERE $where_sql"; $stmt_count = db()->prepare($count_query); $stmt_count->execute($params); $total_records = $stmt_count->fetchColumn(); @@ -210,7 +210,7 @@ $total_pages = ceil($total_records / $limit); // Fetch paginated results $query = "SELECT m.*, s.name as status_name, s.color as status_color, u.full_name as assigned_to_name - FROM mailbox m + FROM outbound_mail m LEFT JOIN mailbox_statuses s ON m.status_id = s.id LEFT JOIN users u ON m.assigned_to = u.id WHERE $where_sql @@ -227,7 +227,7 @@ $users_list = db()->query("SELECT id, full_name FROM users ORDER BY full_name")- $deepLinkData = null; if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id'])) { if (canEdit('outbound')) { - $stmt = db()->prepare("SELECT * FROM mailbox WHERE id = ? AND type = 'outbound'"); + $stmt = db()->prepare("SELECT * FROM outbound_mail WHERE id = ? "); $stmt->execute([$_GET['id']]); $deepLinkData = $stmt->fetch(); } @@ -428,7 +428,7 @@ function getStatusBadgeInList($mail) {
- +
diff --git a/overdue_report.php b/overdue_report.php index f36fbc0..baef4b6 100644 --- a/overdue_report.php +++ b/overdue_report.php @@ -8,30 +8,49 @@ if (!canView('reports')) { $type_filter = $_GET['type'] ?? ''; $user_filter = $_GET['user_id'] ?? ''; -$params = []; -$where = ["m.due_date < CURDATE()", "s.name != 'closed'", "m.type != 'internal'"]; +$overdue_items = []; +$queries = []; -if ($type_filter) { - $where[] = "m.type = ?"; - $params[] = $type_filter; +if (!$type_filter || $type_filter === 'inbound') { + $where = ["m.due_date < CURDATE()", "s.name != 'closed'"]; + $params = []; + if ($user_filter) { + $where[] = "m.assigned_to = ?"; + $params[] = $user_filter; + } + $where_clause = implode(" AND ", $where); + $sql = "SELECT m.*, 'inbound' as type, u.full_name as assigned_name, s.name as status_name, s.color as status_color + FROM inbound_mail m + LEFT JOIN users u ON m.assigned_to = u.id + LEFT JOIN mailbox_statuses s ON m.status_id = s.id + WHERE $where_clause"; + $stmt = db()->prepare($sql); + $stmt->execute($params); + $overdue_items = array_merge($overdue_items, $stmt->fetchAll()); } -if ($user_filter) { - $where[] = "m.assigned_to = ?"; - $params[] = $user_filter; +if (!$type_filter || $type_filter === 'outbound') { + $where = ["m.due_date < CURDATE()", "s.name != 'closed'"]; + $params = []; + if ($user_filter) { + $where[] = "m.assigned_to = ?"; + $params[] = $user_filter; + } + $where_clause = implode(" AND ", $where); + $sql = "SELECT m.*, 'outbound' as type, u.full_name as assigned_name, s.name as status_name, s.color as status_color + FROM outbound_mail m + LEFT JOIN users u ON m.assigned_to = u.id + LEFT JOIN mailbox_statuses s ON m.status_id = s.id + WHERE $where_clause"; + $stmt = db()->prepare($sql); + $stmt->execute($params); + $overdue_items = array_merge($overdue_items, $stmt->fetchAll()); } -$where_clause = implode(" AND ", $where); -$sql = "SELECT m.*, u.full_name as assigned_name, s.name as status_name, s.color as status_color - FROM mailbox m - LEFT JOIN users u ON m.assigned_to = u.id - LEFT JOIN mailbox_statuses s ON m.status_id = s.id - WHERE $where_clause - ORDER BY m.due_date ASC"; - -$stmt = db()->prepare($sql); -$stmt->execute($params); -$overdue_items = $stmt->fetchAll(); +// Sort by due date +usort($overdue_items, function($a, $b) { + return strtotime($a['due_date']) - strtotime($b['due_date']); +}); // Fetch all users for filter $users = db()->query("SELECT id, full_name FROM users ORDER BY full_name")->fetchAll(); @@ -40,7 +59,6 @@ function getStatusBadgeForReport($item) { $status_name = $item['status_name'] ?? 'غير معروف'; $status_color = $item['status_color'] ?? '#6c757d'; - // Translation for default statuses $display_name = $status_name; if ($status_name == 'received') $display_name = 'تم الاستلام'; if ($status_name == 'in_progress') $display_name = 'قيد المعالجة'; @@ -126,7 +144,7 @@ function getStatusBadgeForReport($item) {
يوم - + عرض
@@ -269,14 +269,13 @@ function getStatusBadge($mail) { - عرض + عرض
- أنت على اطلاع بكافة مهامك! لا توجد مهام معلقة.