diff --git a/charity-settings.php b/charity-settings.php index 351824f..9cb3f8b 100644 --- a/charity-settings.php +++ b/charity-settings.php @@ -13,7 +13,8 @@ $error_msg = ''; // Handle Re-enable SMTP if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_smtp'])) { db()->query("UPDATE smtp_settings SET is_enabled = 1, consecutive_failures = 0 WHERE id = 1"); - $success_msg = 'تم إعادة تفعيل SMTP وتصفير عداد الأخطاء'; + $_SESSION['success'] = 'تم إعادة تفعيل SMTP وتصفير عداد الأخطاء'; + redirect('charity-settings.php'); } // Fetch charity settings @@ -54,9 +55,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_charity'])) { $stmt = db()->prepare("UPDATE charity_settings SET charity_name = ?, charity_email = ?, charity_phone = ?, charity_address = ?, charity_logo = ?, charity_favicon = ? WHERE id = 1"); $stmt->execute([$charity_name, $charity_email, $charity_phone, $charity_address, $charity_logo, $charity_favicon]); - $success_msg = 'تم تحديث إعدادات الجمعية بنجاح'; - $stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1"); - $charity = $stmt->fetch(); + $_SESSION['success'] = 'تم تحديث إعدادات الجمعية بنجاح'; + redirect('charity-settings.php'); } // Handle SMTP Settings Update @@ -73,9 +73,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_smtp'])) { $_POST['reply_to'], (int)$_POST['max_failures'] ]); - $success_msg = 'تم تحديث إعدادات البريد (SMTP) بنجاح'; - $stmt = db()->query("SELECT * FROM smtp_settings WHERE id = 1"); - $smtp = $stmt->fetch(); + $_SESSION['success'] = 'تم تحديث إعدادات البريد (SMTP) بنجاح'; + redirect('charity-settings.php'); } // Handle Test Email @@ -83,10 +82,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['test_email_addr'])) { $to = $_POST['test_email_addr']; $res = MailService::sendMail($to, "رسالة تجريبية - Test Email", "

إذا كنت ترى هذه الرسالة، فإن إعدادات SMTP تعمل بشكل صحيح.

"); if ($res['success']) { - $success_msg = "تم إرسال الرسالة التجريبية بنجاح إلى $to"; + $_SESSION['success'] = "تم إرسال الرسالة التجريبية بنجاح إلى $to"; } else { - $error_msg = "فشل إرسال الرسالة التجريبية: " . $res['error']; + $_SESSION['error'] = "فشل إرسال الرسالة التجريبية: " . $res['error']; } + redirect('charity-settings.php'); } // Handle Status Operations @@ -97,7 +97,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_status'])) { if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0"); $stmt = db()->prepare("INSERT INTO mailbox_statuses (name, color, is_default) VALUES (?, ?, ?)"); $stmt->execute([$name, $color, $is_default]); - $success_msg = 'تم إضافة نوع الحالة بنجاح'; + $_SESSION['success'] = 'تم إضافة نوع الحالة بنجاح'; + redirect('charity-settings.php'); } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) { @@ -108,7 +109,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) { if ($is_default) db()->query("UPDATE mailbox_statuses SET is_default = 0"); $stmt = db()->prepare("UPDATE mailbox_statuses SET name = ?, color = ?, is_default = ? WHERE id = ?"); $stmt->execute([$name, $color, $is_default, $id]); - $success_msg = 'تم تحديث نوع الحالة بنجاح'; + $_SESSION['success'] = 'تم تحديث نوع الحالة بنجاح'; + redirect('charity-settings.php'); } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_status'])) { @@ -116,11 +118,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_status'])) { $count = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?"); $count->execute([$id]); if ($count->fetchColumn() > 0) { - $error_msg = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات'; + $_SESSION['error'] = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات'; } else { db()->prepare("DELETE FROM mailbox_statuses WHERE id = ?")->execute([$id]); - $success_msg = 'تم حذف نوع الحالة بنجاح'; + $_SESSION['success'] = 'تم حذف نوع الحالة بنجاح'; } + redirect('charity-settings.php'); +} + +// Get session messages +if (isset($_SESSION['success'])) { + $success_msg = $_SESSION['success']; + unset($_SESSION['success']); +} +if (isset($_SESSION['error'])) { + $error_msg = $_SESSION['error']; + unset($_SESSION['error']); } $statuses = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll(); @@ -392,6 +405,23 @@ function editStatus(id, name, color, isDefault) { document.getElementById('edit_is_default').checked = isDefault == 1; new bootstrap.Modal(document.getElementById('editStatusModal')).show(); } + +document.addEventListener('DOMContentLoaded', function() { + // Preserve active tab after redirect + var activeTab = localStorage.getItem('activeSettingsTab'); + if (activeTab) { + var tabEl = document.querySelector('button[data-bs-target="' + activeTab + '"]'); + if (tabEl) { + bootstrap.Tab.getInstance(tabEl)?.show() || new bootstrap.Tab(tabEl).show(); + } + } + + document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(function(tab) { + tab.addEventListener('shown.bs.tab', function(e) { + localStorage.setItem('activeSettingsTab', e.target.getAttribute('data-bs-target')); + }); + }); +}); - \ No newline at end of file + diff --git a/db/config.php b/db/config.php index 9daa4eb..314db1e 100644 --- a/db/config.php +++ b/db/config.php @@ -15,3 +15,30 @@ function db() { } return $pdo; } + +/** + * Generates the next reference number for a given type (inbound/outbound/internal) + * Format: IN-Year-Serial or OUT-Year-Serial or INT-Year-Serial + */ +function generateRefNo($type) { + $prefix = 'IN'; + if ($type === 'outbound') $prefix = 'OUT'; + if ($type === 'internal') $prefix = 'INT'; + + $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]); + $last_ref = $stmt->fetchColumn(); + + $serial = 1; + if ($last_ref) { + $parts = explode('-', $last_ref); + if (count($parts) === 3) { + $serial = (int)$parts[2] + 1; + } + } + + return $prefix . '-' . $year . '-' . str_pad($serial, 3, '0', STR_PAD_LEFT); +} \ No newline at end of file diff --git a/db/migrations/012_add_internal_mail_type.sql b/db/migrations/012_add_internal_mail_type.sql new file mode 100644 index 0000000..db64e35 --- /dev/null +++ b/db/migrations/012_add_internal_mail_type.sql @@ -0,0 +1,2 @@ +-- Migration: Add internal mail type to mailbox table +ALTER TABLE mailbox MODIFY COLUMN type ENUM('inbound', 'outbound', 'internal') NOT NULL; diff --git a/inbound.php b/inbound.php index 56a389b..ca32d1d 100644 --- a/inbound.php +++ b/inbound.php @@ -79,7 +79,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { sendAssignmentNotification($assigned_to, $ref_no, $subject); } - $success = 'تمت إضافة البريد بنجاح'; + $_SESSION['success'] = 'تمت إضافة البريد بنجاح'; + redirect('inbound.php'); } elseif ($action === 'edit') { // Get previous assigned_to to check if it changed $stmt_old = db()->prepare("SELECT assigned_to FROM mailbox WHERE id = ?"); @@ -93,7 +94,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { sendAssignmentNotification($assigned_to, $ref_no, $subject); } - $success = 'تم تحديث البيانات بنجاح'; + $_SESSION['success'] = 'تم تحديث البيانات بنجاح'; + redirect('inbound.php'); } } catch (PDOException $e) { if ($e->getCode() == 23000) { @@ -116,10 +118,21 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id']) $id = $_GET['id']; $stmt = db()->prepare("DELETE FROM mailbox WHERE id = ? AND type = 'inbound'"); $stmt->execute([$id]); - $success = 'تم حذف البريد بنجاح'; + $_SESSION['success'] = 'تم حذف البريد بنجاح'; + redirect('inbound.php'); } } +// Get session messages +if (isset($_SESSION['success'])) { + $success = $_SESSION['success']; + unset($_SESSION['success']); +} +if (isset($_SESSION['error'])) { + $error = $_SESSION['error']; + unset($_SESSION['error']); +} + $search = $_GET['search'] ?? ''; $my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1; @@ -345,7 +358,7 @@ function getStatusBadgeInList($mail) {
- +
@@ -443,6 +456,7 @@ function openMailModal(action, data = null) { Object.keys(fields).forEach(key => { if (key === 'date_registered') fields[key].value = ''; else if (key === 'status_id') fields[key].value = ''; + else if (key === 'ref_no') fields[key].value = ''; else fields[key].value = ''; }); } else { @@ -513,4 +527,4 @@ function confirmDelete(id) { } - \ No newline at end of file + diff --git a/includes/header.php b/includes/header.php index 9d61826..ec3875b 100644 --- a/includes/header.php +++ b/includes/header.php @@ -53,10 +53,10 @@ if (isLoggedIn()) { $current_user = $stmt->fetch(); // Update session permissions - $_SESSION['can_view'] = $current_user['can_view']; - $_SESSION['can_add'] = $current_user['can_add']; - $_SESSION['can_edit'] = $current_user['can_edit']; - $_SESSION['can_delete'] = $current_user['can_delete']; + $_SESSION['can_view'] = $current_user['can_view'] ?? 1; + $_SESSION['can_add'] = $current_user['can_add'] ?? 0; + $_SESSION['can_edit'] = $current_user['can_edit'] ?? 0; + $_SESSION['can_delete'] = $current_user['can_delete'] ?? 0; } $user_theme = $current_user['theme'] ?? 'light'; ?> @@ -233,6 +233,16 @@ $user_theme = $current_user['theme'] ?? 'light'; color: var(--text-color) !important; } + .sidebar-heading { + padding: 0.5rem 1.5rem; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.05rem; + font-weight: 700; + color: var(--muted-text); + margin-top: 1rem; + } + /* Theme Switcher Styles */ .theme-switcher { padding: 1rem 1.5rem; @@ -274,10 +284,12 @@ $user_theme = $current_user['theme'] ?? 'light'; -
+
\ No newline at end of file diff --git a/internal_inbox.php b/internal_inbox.php new file mode 100644 index 0000000..02e3e81 --- /dev/null +++ b/internal_inbox.php @@ -0,0 +1,164 @@ +prepare("SELECT COUNT(*) FROM mailbox 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 + 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 + ORDER BY m.created_at DESC + LIMIT $limit OFFSET $offset"; + +$stmt = db()->prepare($query); +$stmt->execute($params); +$messages = $stmt->fetchAll(); + +function getStatusBadgeInternal($mail) { + $status_name = $mail['status_name'] ?? 'received'; + $status_color = $mail['status_color'] ?? '#6c757d'; + + $display_name = $status_name; + if ($status_name == 'received') $display_name = 'جديد'; + if ($status_name == 'in_progress') $display_name = 'قيد المعالجة'; + if ($status_name == 'closed') $display_name = 'مؤرشف'; + + return '' . htmlspecialchars($display_name) . ''; +} +?> + + + + + + + +
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
المرسلالموضوعالتاريخالحالةالإجراء
+
+ + + +
+ +
+ + +
+
+
+ + + +
+ + + عرض +
+ +

لا توجد رسائل واردة حالياً

+
+
+
+ 1): ?> + + +
+ + diff --git a/internal_outbox.php b/internal_outbox.php new file mode 100644 index 0000000..23fb653 --- /dev/null +++ b/internal_outbox.php @@ -0,0 +1,296 @@ +query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1; + + if ($recipient_id && $subject) { + try { + $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]); + + // Notify recipient + $stmt_recp = db()->prepare("SELECT full_name, email FROM users WHERE id = ?"); + $stmt_recp->execute([$recipient_id]); + $recipient = $stmt_recp->fetch(); + + if ($recipient && !empty($recipient['email'])) { + $email_subject = "رسالة داخلية جديدة من " . $_SESSION['username']; + $htmlBody = " +
+

لديك رسالة داخلية جديدة

+

الموضوع: " . htmlspecialchars($subject) . "

+

المرسل: " . htmlspecialchars($_SESSION['username']) . "

+
+
" . $description . "
+
+

يمكنك الرد من خلال النظام.

+
+ "; + MailService::sendMail($recipient['email'], $email_subject, $htmlBody); + } + + $_SESSION['success'] = 'تم إرسال الرسالة بنجاح'; + redirect('internal_outbox.php'); + } catch (PDOException $e) { + $error = 'حدث خطأ: ' . $e->getMessage(); + } + } else { + $error = 'يرجى اختيار المرسل إليه وكتابة الموضوع'; + } +} + +// Get session messages +if (isset($_SESSION['success'])) { + $success = $_SESSION['success']; + unset($_SESSION['success']); +} +if (isset($_SESSION['error'])) { + $error = $_SESSION['error']; + unset($_SESSION['error']); +} + +// Search and filtering +$search = $_GET['search'] ?? ''; +$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1; +$limit = 10; +$offset = ($page - 1) * $limit; + +$params = [$user_id]; +$where = "m.type = 'internal' AND m.created_by = ?"; + +if ($search) { + $where .= " AND (m.subject LIKE ? OR m.description LIKE ? OR u_recp.full_name LIKE ?)"; + $params[] = "%$search%"; + $params[] = "%$search%"; + $params[] = "%$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->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 + 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 + ORDER BY m.created_at DESC + LIMIT $limit OFFSET $offset"; + +$stmt = db()->prepare($query); +$stmt->execute($params); +$messages = $stmt->fetchAll(); + +// Users for compose +$users_list = db()->prepare("SELECT id, full_name, username FROM users WHERE id != ? ORDER BY full_name"); +$users_list->execute([$user_id]); +$users_list = $users_list->fetchAll(); + +function getStatusBadgeInternal($mail) { + $status_name = $mail['status_name'] ?? 'received'; + $status_color = $mail['status_color'] ?? '#6c757d'; + + $display_name = $status_name; + if ($status_name == 'received') $display_name = 'مرسلة'; + if ($status_name == 'in_progress') $display_name = 'قيد المتابعة'; + if ($status_name == 'closed') $display_name = 'مؤرشفة'; + + return '' . htmlspecialchars($display_name) . ''; +} +?> + +
+

بريد الموظفين - الصادر

+
+ +
+
+ + + + + + + + + +
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
المستلمالموضوعالتاريخالحالةالإجراء
+
+ + + +
+ +
+ + +
+
+
+ + + +
+ + + عرض +
+ +

لم يتم إرسال أي رسائل حالياً

+
+
+
+ 1): ?> + + +
+ + + + + + + \ No newline at end of file diff --git a/outbound.php b/outbound.php index 09f49fb..69247f6 100644 --- a/outbound.php +++ b/outbound.php @@ -93,7 +93,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { sendAssignmentNotification($assigned_to, $ref_no, $subject); } - $success = 'تمت إضافة البريد الصادر بنجاح'; + $_SESSION['success'] = 'تمت إضافة البريد الصادر بنجاح'; } elseif ($action === 'edit') { $mail_id = $id; @@ -109,7 +109,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { sendAssignmentNotification($assigned_to, $ref_no, $subject); } - $success = 'تم تحديث البيانات بنجاح'; + $_SESSION['success'] = 'تم تحديث البيانات بنجاح'; } // Handle Attachments @@ -130,6 +130,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } db()->commit(); + redirect('outbound.php'); } catch (PDOException $e) { db()->rollBack(); if ($e->getCode() == 23000) { @@ -152,10 +153,21 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id']) $id = $_GET['id']; $stmt = db()->prepare("DELETE FROM mailbox WHERE id = ? AND type = 'outbound'"); $stmt->execute([$id]); - $success = 'تم حذف البريد بنجاح'; + $_SESSION['success'] = 'تم حذف البريد بنجاح'; + redirect('outbound.php'); } } +// Get session messages +if (isset($_SESSION['success'])) { + $success = $_SESSION['success']; + unset($_SESSION['success']); +} +if (isset($_SESSION['error'])) { + $error = $_SESSION['error']; + unset($_SESSION['error']); +} + $search = $_GET['search'] ?? ''; $my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1; @@ -367,7 +379,7 @@ function getStatusBadgeInList($mail) {