Autosave: 20260227-182025
This commit is contained in:
parent
6d5518a7b7
commit
2900795488
@ -1,20 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/mail/MailService.php';
|
||||||
|
|
||||||
// Only admins can access this page
|
// Only admins can access this page
|
||||||
if (!isAdmin()) {
|
if (!isAdmin()) {
|
||||||
header("Location: index.php");
|
redirect("index.php");
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$success_msg = '';
|
$success_msg = '';
|
||||||
$error_msg = '';
|
$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 وتصفير عداد الأخطاء';
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch charity settings
|
// Fetch charity settings
|
||||||
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
||||||
$charity = $stmt->fetch();
|
$charity = $stmt->fetch();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
// Fetch SMTP settings
|
||||||
|
$stmt = db()->query("SELECT * FROM smtp_settings WHERE id = 1");
|
||||||
|
$smtp = $stmt->fetch();
|
||||||
|
|
||||||
|
// Handle Charity Settings Update
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_charity'])) {
|
||||||
$charity_name = $_POST['charity_name'];
|
$charity_name = $_POST['charity_name'];
|
||||||
$charity_email = $_POST['charity_email'];
|
$charity_email = $_POST['charity_email'];
|
||||||
$charity_phone = $_POST['charity_phone'];
|
$charity_phone = $_POST['charity_phone'];
|
||||||
@ -25,7 +36,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$upload_dir = 'uploads/charity/';
|
$upload_dir = 'uploads/charity/';
|
||||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||||
|
|
||||||
// Handle Logo Upload
|
|
||||||
if (isset($_FILES['charity_logo']) && $_FILES['charity_logo']['error'] === UPLOAD_ERR_OK) {
|
if (isset($_FILES['charity_logo']) && $_FILES['charity_logo']['error'] === UPLOAD_ERR_OK) {
|
||||||
$file_ext = pathinfo($_FILES['charity_logo']['name'], PATHINFO_EXTENSION);
|
$file_ext = pathinfo($_FILES['charity_logo']['name'], PATHINFO_EXTENSION);
|
||||||
$new_logo = 'logo_' . time() . '.' . $file_ext;
|
$new_logo = 'logo_' . time() . '.' . $file_ext;
|
||||||
@ -34,7 +44,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Favicon Upload
|
|
||||||
if (isset($_FILES['charity_favicon']) && $_FILES['charity_favicon']['error'] === UPLOAD_ERR_OK) {
|
if (isset($_FILES['charity_favicon']) && $_FILES['charity_favicon']['error'] === UPLOAD_ERR_OK) {
|
||||||
$file_ext = pathinfo($_FILES['charity_favicon']['name'], PATHINFO_EXTENSION);
|
$file_ext = pathinfo($_FILES['charity_favicon']['name'], PATHINFO_EXTENSION);
|
||||||
$new_favicon = 'favicon_' . time() . '.' . $file_ext;
|
$new_favicon = 'favicon_' . time() . '.' . $file_ext;
|
||||||
@ -46,72 +55,343 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$stmt = db()->prepare("UPDATE charity_settings SET charity_name = ?, charity_email = ?, charity_phone = ?, charity_address = ?, charity_logo = ?, charity_favicon = ? WHERE id = 1");
|
$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]);
|
$stmt->execute([$charity_name, $charity_email, $charity_phone, $charity_address, $charity_logo, $charity_favicon]);
|
||||||
$success_msg = 'تم تحديث إعدادات الجمعية بنجاح';
|
$success_msg = 'تم تحديث إعدادات الجمعية بنجاح';
|
||||||
|
|
||||||
// Refresh charity data
|
|
||||||
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
||||||
$charity = $stmt->fetch();
|
$charity = $stmt->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle SMTP Settings Update
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_smtp'])) {
|
||||||
|
$stmt = db()->prepare("UPDATE smtp_settings SET smtp_host = ?, smtp_port = ?, smtp_secure = ?, smtp_user = ?, smtp_pass = ?, from_email = ?, from_name = ?, reply_to = ?, max_failures = ? WHERE id = 1");
|
||||||
|
$stmt->execute([
|
||||||
|
$_POST['smtp_host'],
|
||||||
|
(int)$_POST['smtp_port'],
|
||||||
|
$_POST['smtp_secure'],
|
||||||
|
$_POST['smtp_user'],
|
||||||
|
$_POST['smtp_pass'],
|
||||||
|
$_POST['from_email'],
|
||||||
|
$_POST['from_name'],
|
||||||
|
$_POST['reply_to'],
|
||||||
|
(int)$_POST['max_failures']
|
||||||
|
]);
|
||||||
|
$success_msg = 'تم تحديث إعدادات البريد (SMTP) بنجاح';
|
||||||
|
$stmt = db()->query("SELECT * FROM smtp_settings WHERE id = 1");
|
||||||
|
$smtp = $stmt->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Test Email
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['test_email_addr'])) {
|
||||||
|
$to = $_POST['test_email_addr'];
|
||||||
|
$res = MailService::sendMail($to, "رسالة تجريبية - Test Email", "<p>إذا كنت ترى هذه الرسالة، فإن إعدادات SMTP تعمل بشكل صحيح.</p>");
|
||||||
|
if ($res['success']) {
|
||||||
|
$success_msg = "تم إرسال الرسالة التجريبية بنجاح إلى $to";
|
||||||
|
} else {
|
||||||
|
$error_msg = "فشل إرسال الرسالة التجريبية: " . $res['error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Status Operations
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_status'])) {
|
||||||
|
$name = $_POST['status_name'];
|
||||||
|
$color = $_POST['status_color'];
|
||||||
|
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||||
|
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 = 'تم إضافة نوع الحالة بنجاح';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
|
||||||
|
$id = $_POST['status_id'];
|
||||||
|
$name = $_POST['status_name'];
|
||||||
|
$color = $_POST['status_color'];
|
||||||
|
$is_default = isset($_POST['is_default']) ? 1 : 0;
|
||||||
|
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 = 'تم تحديث نوع الحالة بنجاح';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_status'])) {
|
||||||
|
$id = $_POST['status_id'];
|
||||||
|
$count = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?");
|
||||||
|
$count->execute([$id]);
|
||||||
|
if ($count->fetchColumn() > 0) {
|
||||||
|
$error_msg = 'لا يمكن حذف هذه الحالة لأنها مستخدمة في بعض السجلات';
|
||||||
|
} else {
|
||||||
|
db()->prepare("DELETE FROM mailbox_statuses WHERE id = ?")->execute([$id]);
|
||||||
|
$success_msg = 'تم حذف نوع الحالة بنجاح';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$statuses = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||||
|
$email_logs = db()->query("SELECT * FROM email_logs ORDER BY id DESC LIMIT 50")->fetchAll();
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 mb-4">
|
<div class="col-md-12 mb-4">
|
||||||
<h2 class="fw-bold"><i class="fas fa-cog me-2"></i> إعدادات الجمعية</h2>
|
<h2 class="fw-bold"><i class="fas fa-cog me-2"></i> الإعدادات</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($success_msg): ?>
|
<?php if ($success_msg): ?>
|
||||||
<div class="alert alert-success"><?= $success_msg ?></div>
|
<div class="alert alert-success"><?= $success_msg ?></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if ($error_msg): ?>
|
||||||
|
<div class="alert alert-danger"><?= $error_msg ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="col-md-8 mx-auto">
|
<div class="col-md-12">
|
||||||
<div class="card p-4">
|
<ul class="nav nav-tabs mb-4" id="settingsTabs" role="tablist">
|
||||||
<h4 class="mb-4">بيانات الجمعية</h4>
|
<li class="nav-item" role="presentation">
|
||||||
<form method="POST" enctype="multipart/form-data">
|
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general" type="button" role="tab">بيانات الجمعية</button>
|
||||||
<div class="row">
|
</li>
|
||||||
<div class="col-md-6 mb-3">
|
<li class="nav-item" role="presentation">
|
||||||
<label class="form-label">اسم الجمعية</label>
|
<button class="nav-link" id="smtp-tab" data-bs-toggle="tab" data-bs-target="#smtp" type="button" role="tab">إعدادات SMTP</button>
|
||||||
<input type="text" name="charity_name" class="form-control" value="<?= htmlspecialchars($charity['charity_name'] ?? '') ?>" required>
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="statuses-tab" data-bs-toggle="tab" data-bs-target="#statuses" type="button" role="tab">حالات البريد</button>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link" id="logs-tab" data-bs-toggle="tab" data-bs-target="#logs" type="button" role="tab">سجلات البريد</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content bg-white p-4 shadow-sm rounded border" id="settingsTabsContent">
|
||||||
|
<!-- General Settings -->
|
||||||
|
<div class="tab-pane show active" id="general" role="tabpanel">
|
||||||
|
<h4 class="mb-4">بيانات الجمعية</h4>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<input type="hidden" name="update_charity" value="1">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">اسم الجمعية</label>
|
||||||
|
<input type="text" name="charity_name" class="form-control" value="<?= htmlspecialchars($charity['charity_name'] ?? '') ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">البريد الإلكتروني للجمعية</label>
|
||||||
|
<input type="email" name="charity_email" class="form-control" value="<?= htmlspecialchars($charity['charity_email'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">البريد الإلكتروني للجمعية</label>
|
<label class="form-label">رقم الهاتف</label>
|
||||||
<input type="email" name="charity_email" class="form-control" value="<?= htmlspecialchars($charity['charity_email'] ?? '') ?>">
|
<input type="text" name="charity_phone" class="form-control" value="<?= htmlspecialchars($charity['charity_phone'] ?? '') ?>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="mb-3">
|
||||||
|
<label class="form-label">العنوان</label>
|
||||||
<div class="mb-3">
|
<textarea name="charity_address" class="form-control" rows="3"><?= htmlspecialchars($charity['charity_address'] ?? '') ?></textarea>
|
||||||
<label class="form-label">رقم الهاتف</label>
|
</div>
|
||||||
<input type="text" name="charity_phone" class="form-control" value="<?= htmlspecialchars($charity['charity_phone'] ?? '') ?>">
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">شعار الجمعية</label>
|
||||||
|
<input type="file" name="charity_logo" class="form-control" accept="image/*">
|
||||||
|
<?php if ($charity['charity_logo']): ?>
|
||||||
|
<div class="mt-2"><img src="<?= $charity['charity_logo'] ?>" alt="Logo" style="max-height: 80px;"></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">أيقونة الموقع (Favicon)</label>
|
||||||
|
<input type="file" name="charity_favicon" class="form-control" accept="image/x-icon,image/png">
|
||||||
|
<?php if ($charity['charity_favicon']): ?>
|
||||||
|
<div class="mt-2"><img src="<?= $charity['charity_favicon'] ?>" alt="Favicon" style="max-height: 32px;"></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-dark">تحديث إعدادات الجمعية</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SMTP Settings -->
|
||||||
|
<div class="tab-pane" id="smtp" role="tabpanel">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h4>إعدادات البريد (SMTP)</h4>
|
||||||
|
<?php if (!$smtp['is_enabled']): ?>
|
||||||
|
<div class="badge bg-danger p-2">
|
||||||
|
<i class="fas fa-exclamation-triangle me-1"></i> SMTP معطل بسبب كثرة الأخطاء
|
||||||
|
<form method="POST" style="display:inline;" class="ms-2">
|
||||||
|
<button type="submit" name="enable_smtp" class="btn btn-sm btn-light">إعادة تفعيل</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="badge bg-success p-2">
|
||||||
|
<i class="fas fa-check-circle me-1"></i> SMTP مفعل (أخطاء: <?= $smtp['consecutive_failures'] ?>/<?= $smtp['max_failures'] ?>)
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<form method="POST">
|
||||||
<label class="form-label">العنوان</label>
|
<input type="hidden" name="update_smtp" value="1">
|
||||||
<textarea name="charity_address" class="form-control" rows="3"><?= htmlspecialchars($charity['charity_address'] ?? '') ?></textarea>
|
<div class="row">
|
||||||
</div>
|
<div class="col-md-8 mb-3">
|
||||||
|
<label class="form-label">SMTP Host</label>
|
||||||
|
<input type="text" name="smtp_host" class="form-control" value="<?= htmlspecialchars($smtp['smtp_host'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label class="form-label">SMTP Port</label>
|
||||||
|
<input type="number" name="smtp_port" class="form-control" value="<?= htmlspecialchars($smtp['smtp_port'] ?? 587) ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">SMTP Security</label>
|
||||||
|
<select name="smtp_secure" class="form-select">
|
||||||
|
<option value="tls" <?= ($smtp['smtp_secure'] ?? '') === 'tls' ? 'selected' : '' ?>>TLS (Recommended)</option>
|
||||||
|
<option value="ssl" <?= ($smtp['smtp_secure'] ?? '') === 'ssl' ? 'selected' : '' ?>>SSL</option>
|
||||||
|
<option value="none" <?= ($smtp['smtp_secure'] ?? '') === 'none' ? 'selected' : '' ?>>None</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Sender Name</label>
|
||||||
|
<input type="text" name="from_name" class="form-control" value="<?= htmlspecialchars($smtp['from_name'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">SMTP Username</label>
|
||||||
|
<input type="text" name="smtp_user" class="form-control" value="<?= htmlspecialchars($smtp['smtp_user'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">SMTP Password</label>
|
||||||
|
<input type="password" name="smtp_pass" class="form-control" value="<?= htmlspecialchars($smtp['smtp_pass'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label class="form-label">From Email</label>
|
||||||
|
<input type="email" name="from_email" class="form-control" value="<?= htmlspecialchars($smtp['from_email'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label class="form-label">Reply-To Email</label>
|
||||||
|
<input type="email" name="reply_to" class="form-control" value="<?= htmlspecialchars($smtp['reply_to'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label class="form-label">حد الأخطاء قبل التعطيل</label>
|
||||||
|
<input type="number" name="max_failures" class="form-control" value="<?= htmlspecialchars($smtp['max_failures'] ?? 5) ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">حفظ إعدادات SMTP</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div class="row">
|
<hr class="my-4">
|
||||||
<div class="col-md-6 mb-3">
|
<h5>اختبار الإرسال</h5>
|
||||||
<label class="form-label">شعار الجمعية</label>
|
<form method="POST">
|
||||||
<input type="file" name="charity_logo" class="form-control" accept="image/*">
|
<div class="input-group" style="max-width: 400px;">
|
||||||
<?php if ($charity['charity_logo']): ?>
|
<input type="email" name="test_email_addr" class="form-control" placeholder="بريد الوجهة" required>
|
||||||
<div class="mt-2 text-center">
|
<button class="btn btn-outline-secondary" type="submit">إرسال تجريبي</button>
|
||||||
<img src="<?= $charity['charity_logo'] ?>" alt="Logo" style="max-height: 80px; border: 1px solid #ddd; padding: 5px;">
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Statuses Settings -->
|
||||||
|
<div class="tab-pane" id="statuses" role="tabpanel">
|
||||||
|
<h4 class="mb-4">أنواع حالات البريد</h4>
|
||||||
|
<form method="POST" class="mb-4 bg-light p-3 rounded">
|
||||||
|
<input type="hidden" name="add_status" value="1">
|
||||||
|
<div class="row g-2 align-items-end">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label class="form-label">اسم الحالة</label>
|
||||||
|
<input type="text" name="status_name" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label class="form-label">اللون</label>
|
||||||
|
<input type="color" name="status_color" class="form-control form-control-color w-100" value="#0d6efd">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 text-center">
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input class="form-check-input" type="checkbox" name="is_default" id="is_default">
|
||||||
|
<label class="form-check-label" for="is_default">افتراضية</label>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
</div>
|
<div class="col-md-2">
|
||||||
<div class="col-md-6 mb-3">
|
<button type="submit" class="btn btn-primary w-100">إضافة</button>
|
||||||
<label class="form-label">أيقونة الموقع (Favicon)</label>
|
</div>
|
||||||
<input type="file" name="charity_favicon" class="form-control" accept="image/x-icon,image/png">
|
|
||||||
<?php if ($charity['charity_favicon']): ?>
|
|
||||||
<div class="mt-2 text-center">
|
|
||||||
<img src="<?= $charity['charity_favicon'] ?>" alt="Favicon" style="max-height: 32px;">
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr><th>الاسم</th><th>اللون</th><th>افتراضية</th><th class="text-end">الإجراء</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($statuses as $status): ?>
|
||||||
|
<tr>
|
||||||
|
<td><span class="badge" style="background-color: <?= $status['color'] ?>;"><?= htmlspecialchars($status['name']) ?></span></td>
|
||||||
|
<td><code><?= $status['color'] ?></code></td>
|
||||||
|
<td><?= $status['is_default'] ? '<i class="fas fa-check text-success"></i>' : '' ?></td>
|
||||||
|
<td class="text-end">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="editStatus(<?= $status['id'] ?>, '<?= htmlspecialchars($status['name'], ENT_QUOTES) ?>', '<?= $status['color'] ?>', <?= $status['is_default'] ?>)"><i class="fas fa-edit"></i></button>
|
||||||
|
<form method="POST" onsubmit="return confirm('حذف؟');" style="display:inline;"><input type="hidden" name="status_id" value="<?= $status['id'] ?>"><input type="hidden" name="delete_status" value="1"><button type="submit" class="btn btn-sm btn-outline-danger"><i class="fas fa-trash"></i></button></form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-dark w-100 mt-4">تحديث إعدادات الجمعية</button>
|
<!-- Email Logs -->
|
||||||
|
<div class="tab-pane" id="logs" role="tabpanel">
|
||||||
|
<h4 class="mb-4">سجلات البريد المرسل (آخر 50 عملية)</h4>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>الوقت</th>
|
||||||
|
<th>المستلم</th>
|
||||||
|
<th>الموضوع</th>
|
||||||
|
<th>الحالة</th>
|
||||||
|
<th>الخطأ</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($email_logs as $log): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="small"><?= date('Y-m-d H:i', strtotime($log['created_at'])) ?></td>
|
||||||
|
<td><?= htmlspecialchars($log['recipient']) ?></td>
|
||||||
|
<td class="small"><?= htmlspecialchars($log['subject']) ?></td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-<?= $log['status'] === 'success' ? 'success' : 'danger' ?>">
|
||||||
|
<?= $log['status'] === 'success' ? 'نجاح' : 'فشل' ?>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="small text-danger"><?= htmlspecialchars($log['error_message'] ?? '') ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="editStatusModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form method="POST">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">تعديل نوع الحالة</h5>
|
||||||
|
<button type="button" class="btn-close ms-0 me-auto" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="hidden" name="update_status" value="1"><input type="hidden" name="status_id" id="edit_status_id">
|
||||||
|
<div class="mb-3"><label class="form-label">اسم الحالة</label><input type="text" name="status_name" id="edit_status_name" class="form-control" required></div>
|
||||||
|
<div class="mb-3"><label class="form-label">اللون</label><input type="color" name="status_color" id="edit_status_color" class="form-control form-control-color w-100"></div>
|
||||||
|
<div class="form-check"><input class="form-check-input" type="checkbox" name="is_default" id="edit_is_default"><label class="form-check-label" for="edit_is_default">افتراضية</label></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||||
|
<button type="submit" class="btn btn-primary">حفظ</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<script>
|
||||||
|
function editStatus(id, name, color, isDefault) {
|
||||||
|
document.getElementById('edit_status_id').value = id;
|
||||||
|
document.getElementById('edit_status_name').value = name;
|
||||||
|
document.getElementById('edit_status_color').value = color;
|
||||||
|
document.getElementById('edit_is_default').checked = isDefault == 1;
|
||||||
|
new bootstrap.Modal(document.getElementById('editStatusModal')).show();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
25
db/migrations/004_add_mailbox_statuses.sql
Normal file
25
db/migrations/004_add_mailbox_statuses.sql
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
-- Migration: Add mailbox statuses table
|
||||||
|
CREATE TABLE IF NOT EXISTS mailbox_statuses (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(50) NOT NULL,
|
||||||
|
color VARCHAR(20) DEFAULT '#000000',
|
||||||
|
is_default BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Insert initial statuses if they don't exist
|
||||||
|
INSERT IGNORE INTO mailbox_statuses (id, name, color, is_default) VALUES
|
||||||
|
(1, 'received', '#6c757d', TRUE),
|
||||||
|
(2, 'in_progress', '#0d6efd', FALSE),
|
||||||
|
(3, 'closed', '#198754', FALSE);
|
||||||
|
|
||||||
|
-- Add status_id to mailbox
|
||||||
|
ALTER TABLE mailbox ADD COLUMN IF NOT EXISTS status_id INT;
|
||||||
|
|
||||||
|
-- Update status_id based on existing ENUM values
|
||||||
|
UPDATE mailbox SET status_id = 1 WHERE status = 'received' AND status_id IS NULL;
|
||||||
|
UPDATE mailbox SET status_id = 2 WHERE status = 'in_progress' AND status_id IS NULL;
|
||||||
|
UPDATE mailbox SET status_id = 3 WHERE status = 'closed' AND status_id IS NULL;
|
||||||
|
|
||||||
|
-- Set default status_id for any NULLs
|
||||||
|
UPDATE mailbox SET status_id = 1 WHERE status_id IS NULL;
|
||||||
2
db/migrations/005_add_due_date_to_mailbox.sql
Normal file
2
db/migrations/005_add_due_date_to_mailbox.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- Migration: Add due_date column to mailbox table
|
||||||
|
ALTER TABLE mailbox ADD COLUMN IF NOT EXISTS due_date DATE NULL;
|
||||||
18
db/migrations/006_add_smtp_settings.sql
Normal file
18
db/migrations/006_add_smtp_settings.sql
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS smtp_settings (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
transport VARCHAR(20) DEFAULT 'smtp',
|
||||||
|
smtp_host VARCHAR(255),
|
||||||
|
smtp_port INT DEFAULT 587,
|
||||||
|
smtp_secure VARCHAR(10) DEFAULT 'tls',
|
||||||
|
smtp_user VARCHAR(255),
|
||||||
|
smtp_pass VARCHAR(255),
|
||||||
|
from_email VARCHAR(255),
|
||||||
|
from_name VARCHAR(255),
|
||||||
|
reply_to VARCHAR(255),
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- Insert default row if not exists
|
||||||
|
INSERT INTO smtp_settings (id, transport, smtp_host, smtp_port, smtp_secure, from_email, from_name)
|
||||||
|
SELECT 1, 'smtp', '', 587, 'tls', 'no-reply@localhost', 'App'
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM smtp_settings WHERE id = 1);
|
||||||
14
db/migrations/007_add_email_logs.sql
Normal file
14
db/migrations/007_add_email_logs.sql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- Create email_logs table
|
||||||
|
CREATE TABLE IF NOT EXISTS email_logs (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
recipient TEXT NOT NULL,
|
||||||
|
subject VARCHAR(255),
|
||||||
|
status ENUM('success', 'failure') NOT NULL,
|
||||||
|
error_message TEXT,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Add consecutive_failures to smtp_settings to track repeated issues
|
||||||
|
ALTER TABLE smtp_settings ADD COLUMN consecutive_failures INT DEFAULT 0;
|
||||||
|
ALTER TABLE smtp_settings ADD COLUMN max_failures INT DEFAULT 5;
|
||||||
|
ALTER TABLE smtp_settings ADD COLUMN is_enabled TINYINT(1) DEFAULT 1;
|
||||||
178
inbound.php
178
inbound.php
@ -1,8 +1,48 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/mail/MailService.php';
|
||||||
|
|
||||||
$error = '';
|
$error = '';
|
||||||
$success = '';
|
$success = '';
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
|
||||||
|
// Fetch statuses
|
||||||
|
$statuses_list = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||||
|
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||||
|
|
||||||
|
// Function to send assignment notification
|
||||||
|
function sendAssignmentNotification($assigned_to_id, $ref_no, $subject) {
|
||||||
|
if (!$assigned_to_id) return;
|
||||||
|
|
||||||
|
$stmt = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$assigned_to_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user && !empty($user['email'])) {
|
||||||
|
$to = $user['email'];
|
||||||
|
$email_subject = "تنبيه: تم تعيين بريد جديد لك (رقم القيد: $ref_no)";
|
||||||
|
$htmlBody = "
|
||||||
|
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||||
|
<h2>مرحباً " . htmlspecialchars($user['full_name']) . "</h2>
|
||||||
|
<p>لقد تم تعيين مهمة بريد جديد لك في النظام.</p>
|
||||||
|
<table border='1' cellpadding='10' cellspacing='0' style='border-collapse: collapse;'>
|
||||||
|
<tr>
|
||||||
|
<th style='background-color: #f8f9fa;'>رقم القيد</th>
|
||||||
|
<td>" . htmlspecialchars($ref_no) . "</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style='background-color: #f8f9fa;'>الموضوع</th>
|
||||||
|
<td>" . htmlspecialchars($subject) . "</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>يرجى الدخول للنظام لمتابعة المهمة.</p>
|
||||||
|
<br>
|
||||||
|
<p>هذا تنبيه تلقائي، يرجى عدم الرد.</p>
|
||||||
|
</div>
|
||||||
|
";
|
||||||
|
MailService::sendMail($to, $email_subject, $htmlBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle actions
|
// Handle actions
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
@ -10,23 +50,39 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$type = 'inbound';
|
$type = 'inbound';
|
||||||
$ref_no = $_POST['ref_no'] ?? '';
|
$ref_no = $_POST['ref_no'] ?? '';
|
||||||
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
||||||
|
$due_date = !empty($_POST['due_date']) ? $_POST['due_date'] : null;
|
||||||
$sender = $_POST['sender'] ?? '';
|
$sender = $_POST['sender'] ?? '';
|
||||||
$recipient = $_POST['recipient'] ?? '';
|
$recipient = $_POST['recipient'] ?? '';
|
||||||
$subject = $_POST['subject'] ?? '';
|
$subject = $_POST['subject'] ?? '';
|
||||||
$description = $_POST['description'] ?? '';
|
$description = $_POST['description'] ?? '';
|
||||||
$status = $_POST['status'] ?? 'received';
|
$status_id = $_POST['status_id'] ?? $default_status_id;
|
||||||
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
||||||
$id = $_POST['id'] ?? 0;
|
$id = $_POST['id'] ?? 0;
|
||||||
|
|
||||||
if ($ref_no && $subject) {
|
if ($ref_no && $subject) {
|
||||||
try {
|
try {
|
||||||
if ($action === 'add') {
|
if ($action === 'add') {
|
||||||
$stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, sender, recipient, subject, description, status, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
$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, $sender, $recipient, $subject, $description, $status, $assigned_to, $_SESSION['user_id']]);
|
$stmt->execute([$type, $ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]);
|
||||||
|
|
||||||
|
if ($assigned_to) {
|
||||||
|
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
$success = 'تمت إضافة البريد بنجاح';
|
$success = 'تمت إضافة البريد بنجاح';
|
||||||
} elseif ($action === 'edit') {
|
} elseif ($action === 'edit') {
|
||||||
$stmt = db()->prepare("UPDATE mailbox SET ref_no = ?, date_registered = ?, sender = ?, recipient = ?, subject = ?, description = ?, status = ?, assigned_to = ? WHERE id = ? AND type = 'inbound'");
|
// Get previous assigned_to to check if it changed
|
||||||
$stmt->execute([$ref_no, $date_registered, $sender, $recipient, $subject, $description, $status, $assigned_to, $id]);
|
$stmt_old = db()->prepare("SELECT assigned_to FROM mailbox 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->execute([$ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $id]);
|
||||||
|
|
||||||
|
if ($assigned_to && $assigned_to != $old_assigned_to) {
|
||||||
|
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
$success = 'تم تحديث البيانات بنجاح';
|
$success = 'تم تحديث البيانات بنجاح';
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
@ -50,13 +106,28 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
$query = "SELECT * FROM mailbox WHERE type = 'inbound'";
|
$my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1;
|
||||||
|
|
||||||
|
$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 = 'inbound'";
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$query .= " AND (ref_no LIKE ? OR sender LIKE ? OR subject LIKE ?)";
|
$query .= " AND (m.ref_no LIKE ? OR m.sender LIKE ? OR m.subject LIKE ?)";
|
||||||
$params = ["%$search%", "%$search%", "%$search%"];
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
}
|
}
|
||||||
$query .= " ORDER BY created_at DESC";
|
|
||||||
|
if ($my_tasks) {
|
||||||
|
$query .= " AND m.assigned_to = ?";
|
||||||
|
$params[] = $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= " ORDER BY m.created_at DESC";
|
||||||
$stmt = db()->prepare($query);
|
$stmt = db()->prepare($query);
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
$mails = $stmt->fetchAll();
|
$mails = $stmt->fetchAll();
|
||||||
@ -70,6 +141,19 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
$stmt->execute([$_GET['id']]);
|
$stmt->execute([$_GET['id']]);
|
||||||
$deepLinkData = $stmt->fetch();
|
$deepLinkData = $stmt->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStatusBadgeInList($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 = 'قيد المعالجة';
|
||||||
|
if ($status_name == 'closed') $display_name = 'مكتمل';
|
||||||
|
|
||||||
|
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
@ -95,13 +179,24 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<div class="card-header bg-white py-3">
|
<div class="card-header bg-white py-3">
|
||||||
<form class="row g-2">
|
<form class="row g-3 align-items-center">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المرسل..." value="<?= htmlspecialchars($search) ?>">
|
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المرسل..." value="<?= htmlspecialchars($search) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-md-3">
|
||||||
<button type="submit" class="btn btn-secondary">بحث</button>
|
<div class="form-check form-switch mt-1">
|
||||||
|
<input class="form-check-input" type="checkbox" name="my_tasks" id="myTasksSwitch" value="1" <?= $my_tasks ? 'checked' : '' ?> onchange="this.form.submit()">
|
||||||
|
<label class="form-check-label fw-bold" for="myTasksSwitch">مهامي فقط</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="submit" class="btn btn-secondary px-4">بحث</button>
|
||||||
|
</div>
|
||||||
|
<?php if ($search || $my_tasks): ?>
|
||||||
|
<div class="col-auto">
|
||||||
|
<a href="inbound.php" class="btn btn-link text-decoration-none">إلغاء التصفية</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
@ -111,8 +206,10 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="ps-4">رقم القيد</th>
|
<th class="ps-4">رقم القيد</th>
|
||||||
<th>التاريخ</th>
|
<th>التاريخ</th>
|
||||||
|
<th>الموعد النهائي</th>
|
||||||
<th>الموضوع</th>
|
<th>الموضوع</th>
|
||||||
<th>المرسل</th>
|
<th>المرسل</th>
|
||||||
|
<th>المسؤول</th>
|
||||||
<th>الحالة</th>
|
<th>الحالة</th>
|
||||||
<th class="pe-4 text-center">الإجراءات</th>
|
<th class="pe-4 text-center">الإجراءات</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -122,21 +219,32 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||||
<td><?= $mail['date_registered'] ?></td>
|
<td><?= $mail['date_registered'] ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($mail['due_date']): ?>
|
||||||
|
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : '' ?>">
|
||||||
|
<?= $mail['due_date'] ?>
|
||||||
|
<?php if (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed'): ?>
|
||||||
|
<i class="fas fa-exclamation-triangle ms-1"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||||
<td><?= htmlspecialchars($mail['sender']) ?></td>
|
<td><?= htmlspecialchars($mail['sender']) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if ($mail['status'] === 'received'): ?>
|
<?php if ($mail['assigned_to_name']): ?>
|
||||||
<span class="badge bg-secondary">تم الاستلام</span>
|
<span class="text-nowrap"><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></span>
|
||||||
<?php elseif ($mail['status'] === 'in_progress'): ?>
|
<?php else: ?>
|
||||||
<span class="badge bg-info text-dark">قيد المعالجة</span>
|
<span class="text-muted">غير معين</span>
|
||||||
<?php elseif ($mail['status'] === 'closed'): ?>
|
|
||||||
<span class="badge bg-success">مكتمل</span>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
|
<td><?= getStatusBadgeInList($mail) ?></td>
|
||||||
<td class="pe-4 text-center">
|
<td class="pe-4 text-center">
|
||||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||||
onclick="openMailModal('edit', <?= htmlspecialchars(json_encode($mail), ENT_QUOTES, 'UTF-8') ?>)" title="تعديل">
|
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||||
@ -144,7 +252,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; else: ?>
|
<?php endforeach; else: ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center py-4 text-muted">لا يوجد بريد وارد مسجل حالياً</td>
|
<td colspan="8" class="text-center py-4 text-muted">لا يوجد بريد وارد مسجل حالياً</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -167,14 +275,18 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<input type="hidden" name="id" id="modalId" value="0">
|
<input type="hidden" name="id" id="modalId" value="0">
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
||||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required>
|
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
||||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-bold">الموعد النهائي</label>
|
||||||
|
<input type="date" name="due_date" id="modalDueDate" class="form-control">
|
||||||
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label fw-bold">المرسل</label>
|
<label class="form-label fw-bold">المرسل</label>
|
||||||
<input type="text" name="sender" id="modalSender" class="form-control">
|
<input type="text" name="sender" id="modalSender" class="form-control">
|
||||||
@ -193,10 +305,16 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label fw-bold">الحالة</label>
|
<label class="form-label fw-bold">الحالة</label>
|
||||||
<select name="status" id="modalStatus" class="form-select">
|
<select name="status_id" id="modalStatusId" class="form-select">
|
||||||
<option value="received">تم الاستلام</option>
|
<?php foreach ($statuses_list as $s): ?>
|
||||||
<option value="in_progress">قيد المعالجة</option>
|
<?php
|
||||||
<option value="closed">مكتمل / مغلق</option>
|
$d_name = $s['name'];
|
||||||
|
if ($d_name == 'received') $d_name = 'تم الاستلام';
|
||||||
|
if ($d_name == 'in_progress') $d_name = 'قيد المعالجة';
|
||||||
|
if ($d_name == 'closed') $d_name = 'مكتمل / مغلق';
|
||||||
|
?>
|
||||||
|
<option value="<?= $s['id'] ?>"><?= htmlspecialchars($d_name) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -240,11 +358,12 @@ function openMailModal(action, data = null) {
|
|||||||
const fields = {
|
const fields = {
|
||||||
ref_no: document.getElementById('modalRefNo'),
|
ref_no: document.getElementById('modalRefNo'),
|
||||||
date_registered: document.getElementById('modalDateRegistered'),
|
date_registered: document.getElementById('modalDateRegistered'),
|
||||||
|
due_date: document.getElementById('modalDueDate'),
|
||||||
sender: document.getElementById('modalSender'),
|
sender: document.getElementById('modalSender'),
|
||||||
recipient: document.getElementById('modalRecipient'),
|
recipient: document.getElementById('modalRecipient'),
|
||||||
subject: document.getElementById('modalSubject'),
|
subject: document.getElementById('modalSubject'),
|
||||||
description: document.getElementById('modalDescription'),
|
description: document.getElementById('modalDescription'),
|
||||||
status: document.getElementById('modalStatus'),
|
status_id: document.getElementById('modalStatusId'),
|
||||||
assigned_to: document.getElementById('modalAssignedTo')
|
assigned_to: document.getElementById('modalAssignedTo')
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,7 +374,7 @@ function openMailModal(action, data = null) {
|
|||||||
modalId.value = '0';
|
modalId.value = '0';
|
||||||
Object.keys(fields).forEach(key => {
|
Object.keys(fields).forEach(key => {
|
||||||
if (key === 'date_registered') fields[key].value = '<?= date('Y-m-d') ?>';
|
if (key === 'date_registered') fields[key].value = '<?= date('Y-m-d') ?>';
|
||||||
else if (key === 'status') fields[key].value = 'received';
|
else if (key === 'status_id') fields[key].value = '<?= $default_status_id ?>';
|
||||||
else fields[key].value = '';
|
else fields[key].value = '';
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -277,11 +396,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
'id' => $_POST['id'] ?? 0,
|
'id' => $_POST['id'] ?? 0,
|
||||||
'ref_no' => $_POST['ref_no'] ?? '',
|
'ref_no' => $_POST['ref_no'] ?? '',
|
||||||
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
||||||
|
'due_date' => $_POST['due_date'] ?? '',
|
||||||
'sender' => $_POST['sender'] ?? '',
|
'sender' => $_POST['sender'] ?? '',
|
||||||
'recipient' => $_POST['recipient'] ?? '',
|
'recipient' => $_POST['recipient'] ?? '',
|
||||||
'subject' => $_POST['subject'] ?? '',
|
'subject' => $_POST['subject'] ?? '',
|
||||||
'description' => $_POST['description'] ?? '',
|
'description' => $_POST['description'] ?? '',
|
||||||
'status' => $_POST['status'] ?? 'received',
|
'status_id' => $_POST['status_id'] ?? $default_status_id,
|
||||||
'assigned_to' => $_POST['assigned_to'] ?? ''
|
'assigned_to' => $_POST['assigned_to'] ?? ''
|
||||||
]) ?>;
|
]) ?>;
|
||||||
openMailModal('<?= $_POST['action'] ?>', errorData);
|
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||||
|
|||||||
@ -44,16 +44,16 @@ if (isLoggedIn()) {
|
|||||||
<link rel="icon" type="image/x-icon" href="<?= $charity_favicon ?>?v=<?= time() ?>">
|
<link rel="icon" type="image/x-icon" href="<?= $charity_favicon ?>?v=<?= time() ?>">
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<!-- Bootstrap 5 RTL CSS -->
|
<!-- Bootstrap 5 RTL CSS -->
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css?v=<?php echo time(); ?>">
|
||||||
<!-- Google Fonts: Cairo -->
|
<!-- Google Fonts: Cairo -->
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap" rel="stylesheet">
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css?v=<?php echo time(); ?>">
|
||||||
|
|
||||||
<!-- JS Libraries (Loaded in head to support inline onclick handlers) -->
|
<!-- JS Libraries (Loaded in head to support inline onclick handlers) -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js?v=<?php echo time(); ?>"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"></script>
|
<script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js?v=<?php echo time(); ?>"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@ -113,7 +113,7 @@ if (isLoggedIn()) {
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<?php if (isLoggedIn()): ?>
|
<?php if (isLoggedIn()): ?>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<nav class="col-md-3 col-lg-2 d-md-block sidebar collapse">
|
<nav class="col-md-3 col-lg-2 d-md-block sidebar">
|
||||||
<div class="position-sticky">
|
<div class="position-sticky">
|
||||||
<div class="text-center mb-4">
|
<div class="text-center mb-4">
|
||||||
<?php if ($charity_logo): ?>
|
<?php if ($charity_logo): ?>
|
||||||
@ -131,12 +131,18 @@ if (isLoggedIn()) {
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<div class="small fw-bold"><?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['username']) ?></div>
|
<div class="small fw-bold"><?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['username']) ?></div>
|
||||||
<div class="small text-muted"><?= $_SESSION['user_role'] === 'admin' ? 'مدير النظام' : 'موظف' ?></div>
|
<div class="small text-muted">
|
||||||
|
<?php
|
||||||
|
if ($_SESSION['user_role'] === 'admin') echo 'مدير النظام';
|
||||||
|
elseif ($_SESSION['user_role'] === 'clerk') echo 'كاتب';
|
||||||
|
else echo 'موظف';
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'index.php' ? 'active' : '' ?>" href="index.php">
|
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'index.php' || basename($_SERVER['PHP_SELF']) == 'user_dashboard.php') ? 'active' : '' ?>" href="index.php">
|
||||||
<i class="fas fa-home me-2"></i> لوحة التحكم
|
<i class="fas fa-home me-2"></i> لوحة التحكم
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -151,6 +157,11 @@ if (isLoggedIn()) {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if (isAdmin()): ?>
|
<?php if (isAdmin()): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'overdue_report.php' ? 'active' : '' ?>" href="overdue_report.php">
|
||||||
|
<i class="fas fa-chart-line me-2"></i> تقرير التأخير
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : '' ?>" href="users.php">
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : '' ?>" href="users.php">
|
||||||
<i class="fas fa-users me-2"></i> إدارة المستخدمين
|
<i class="fas fa-users me-2"></i> إدارة المستخدمين
|
||||||
@ -177,4 +188,4 @@ if (isLoggedIn()) {
|
|||||||
</nav>
|
</nav>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<main class="<?= isLoggedIn() ? 'col-md-9 ms-sm-auto col-lg-10' : 'col-12' ?> px-md-4 py-4">
|
<nav class="navbar navbar-expand-md navbar-light bg-white d-md-none border-bottom mb-3"><div class="container-fluid"><span class="navbar-brand">القائمة</span><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".sidebar" aria-controls="sidebar" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button></div></nav><main class="<?= isLoggedIn() ? 'col-md-9 ms-sm-auto col-lg-10' : 'col-12' ?> px-md-4 py-4">
|
||||||
174
index.php
174
index.php
@ -1,32 +1,101 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
if (!isAdmin()) { redirect('user_dashboard.php'); }
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$is_admin = isAdmin();
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
$total_inbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn();
|
$total_inbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn();
|
||||||
$total_outbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn();
|
$total_outbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn();
|
||||||
$in_progress = db()->query("SELECT COUNT(*) FROM mailbox WHERE status = 'in_progress'")->fetchColumn();
|
|
||||||
$recent_mail = db()->query("SELECT * FROM mailbox ORDER BY created_at DESC LIMIT 5")->fetchAll();
|
|
||||||
|
|
||||||
function getStatusBadge($status) {
|
// Fetch statuses for badge and count
|
||||||
switch ($status) {
|
$statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE);
|
||||||
case 'received': return '<span class="badge bg-secondary">تم الاستلام</span>';
|
|
||||||
case 'in_progress': return '<span class="badge bg-info text-dark">قيد المعالجة</span>';
|
// For the "In Progress" stat card, we might need a specific status or just a sum of non-closed statuses.
|
||||||
case 'closed': return '<span class="badge bg-success">مكتمل</span>';
|
$in_progress_id = null;
|
||||||
default: return '<span class="badge bg-dark">غير معروف</span>';
|
foreach ($statuses_data as $id => $s) {
|
||||||
|
if ($s['name'] == 'in_progress') {
|
||||||
|
$in_progress_id = $id;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$in_progress_count = 0;
|
||||||
|
if ($in_progress_id) {
|
||||||
|
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE status_id = ?");
|
||||||
|
$stmt->execute([$in_progress_id]);
|
||||||
|
$in_progress_count = $stmt->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// My Assignments
|
||||||
|
$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 = ?
|
||||||
|
ORDER BY m.created_at DESC LIMIT 5");
|
||||||
|
$my_assignments->execute([$user_id]);
|
||||||
|
$my_assignments = $my_assignments->fetchAll();
|
||||||
|
|
||||||
|
// Recent Mail (Global for Admin/Clerk, otherwise limited)
|
||||||
|
$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";
|
||||||
|
if (!$is_admin && $_SESSION['user_role'] !== 'clerk') {
|
||||||
|
$recent_mail_query .= " WHERE 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]);
|
||||||
|
} else {
|
||||||
|
$recent_stmt = db()->prepare($recent_mail_query . " ORDER BY m.created_at DESC LIMIT 10");
|
||||||
|
$recent_stmt->execute();
|
||||||
|
}
|
||||||
|
$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 = 'قيد المعالجة';
|
||||||
|
if ($status_name == 'closed') $display_name = 'مكتمل';
|
||||||
|
|
||||||
|
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<h1 class="h2">لوحة التحكم</h1>
|
<h1 class="h2">لوحة التحكم</h1>
|
||||||
<div class="btn-toolbar mb-2 mb-md-0">
|
<div class="btn-toolbar mb-2 mb-md-0">
|
||||||
<div class="btn-group me-2">
|
<div class="btn-group me-2">
|
||||||
|
<?php if (isAdmin()): ?><a href="charity-settings.php" class="btn btn-sm btn-outline-dark"><i class="fas fa-cog me-1"></i> الإعدادات</a><?php endif; ?>
|
||||||
<a href="inbound.php?action=add" class="btn btn-sm btn-outline-primary">إضافة بريد وارد</a>
|
<a href="inbound.php?action=add" class="btn btn-sm btn-outline-primary">إضافة بريد وارد</a>
|
||||||
<a href="outbound.php?action=add" class="btn btn-sm btn-outline-secondary">إضافة بريد صادر</a>
|
<a href="outbound.php" class="btn btn-sm btn-outline-secondary">إضافة بريد صادر</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Overdue Alert -->
|
||||||
|
<?php
|
||||||
|
$overdue_count = db()->query("SELECT COUNT(*) FROM mailbox WHERE due_date < CURDATE() AND status != 'closed'")->fetchColumn();
|
||||||
|
if ($overdue_count > 0):
|
||||||
|
?>
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="alert alert-danger shadow-sm border-0 d-flex align-items-center justify-content-between mb-0">
|
||||||
|
<div>
|
||||||
|
<i class="fas fa-exclamation-triangle fs-4 me-3"></i>
|
||||||
|
<span class="fw-bold">هناك <?= $overdue_count ?> مهام متأخرة تتطلب انتباهك!</span>
|
||||||
|
</div>
|
||||||
|
<?php if (isAdmin()): ?>
|
||||||
|
<a href="overdue_report.php" class="btn btn-danger btn-sm">عرض التقرير</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Stats Cards -->
|
<!-- Stats Cards -->
|
||||||
<div class="row g-4 mb-4">
|
<div class="row g-4 mb-4">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
@ -60,7 +129,7 @@ function getStatusBadge($status) {
|
|||||||
<div class="d-flex align-items-center justify-content-between">
|
<div class="d-flex align-items-center justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<h6 class="text-muted mb-1">قيد المعالجة</h6>
|
<h6 class="text-muted mb-1">قيد المعالجة</h6>
|
||||||
<h3 class="fw-bold mb-0"><?= $in_progress ?></h3>
|
<h3 class="fw-bold mb-0"><?= $in_progress_count ?></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-info bg-opacity-10 p-3 rounded-circle">
|
<div class="bg-info bg-opacity-10 p-3 rounded-circle">
|
||||||
<i class="fas fa-clock text-info fs-4"></i>
|
<i class="fas fa-clock text-info fs-4"></i>
|
||||||
@ -83,12 +152,61 @@ function getStatusBadge($status) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($my_assignments)): ?>
|
||||||
|
<!-- My Assignments Section -->
|
||||||
|
<div class="card shadow-sm border-0 mb-4 bg-primary bg-opacity-10 border-top border-primary border-3">
|
||||||
|
<div class="card-header bg-transparent py-3 border-0">
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 fw-bold text-primary"><i class="fas fa-tasks me-2"></i> مهامي الحالية</h5>
|
||||||
|
<span class="badge bg-primary rounded-pill"><?= count($my_assignments) ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($my_assignments as $mail): ?>
|
||||||
|
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||||
|
<td class="ps-4" width="120">
|
||||||
|
<small class="text-muted d-block">رقم القيد</small>
|
||||||
|
<span class="fw-bold text-primary"><?= $mail['ref_no'] ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<small class="text-muted d-block">الموضوع</small>
|
||||||
|
<span class="fw-bold"><?= htmlspecialchars($mail['subject']) ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<small class="text-muted d-block">الموعد النهائي</small>
|
||||||
|
<?php if ($mail['due_date']): ?>
|
||||||
|
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : '' ?>">
|
||||||
|
<?= $mail['due_date'] ?>
|
||||||
|
</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<small class="text-muted d-block mb-1">الحالة</small>
|
||||||
|
<?= getStatusBadge($mail) ?>
|
||||||
|
</td>
|
||||||
|
<td class="pe-4 text-end">
|
||||||
|
<i class="fas fa-chevron-left text-primary"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Recent Mail -->
|
<!-- Recent Mail -->
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<div class="card-header bg-white py-3">
|
<div class="card-header bg-white py-3">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<h5 class="mb-0 fw-bold">البريد المضاف حديثاً</h5>
|
<h5 class="mb-0 fw-bold"><?= $is_admin ? 'آخر المراسلات المسجلة' : 'آخر المراسلات' ?></h5>
|
||||||
<a href="inbound.php" class="btn btn-sm btn-link">عرض الكل</a>
|
<a href="inbound.php" class="btn btn-sm btn-link text-decoration-none">عرض الكل</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
@ -99,7 +217,9 @@ function getStatusBadge($status) {
|
|||||||
<th class="ps-4">رقم القيد</th>
|
<th class="ps-4">رقم القيد</th>
|
||||||
<th>النوع</th>
|
<th>النوع</th>
|
||||||
<th>الموضوع</th>
|
<th>الموضوع</th>
|
||||||
|
<th>الموعد النهائي</th>
|
||||||
<th>المرسل/المستلم</th>
|
<th>المرسل/المستلم</th>
|
||||||
|
<th>المسؤول</th>
|
||||||
<th>الحالة</th>
|
<th>الحالة</th>
|
||||||
<th class="pe-4 text-center">التاريخ</th>
|
<th class="pe-4 text-center">التاريخ</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -109,16 +229,38 @@ function getStatusBadge($status) {
|
|||||||
<?php foreach ($recent_mail as $mail): ?>
|
<?php foreach ($recent_mail as $mail): ?>
|
||||||
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||||
<td><?= $mail['type'] == 'inbound' ? 'وارد' : 'صادر' ?></td>
|
<td>
|
||||||
|
<?php if ($mail['type'] == 'inbound'): ?>
|
||||||
|
<span class="text-primary"><i class="fas fa-arrow-down me-1"></i> وارد</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-success"><i class="fas fa-arrow-up me-1"></i> صادر</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($mail['due_date']): ?>
|
||||||
|
<small class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : 'text-muted' ?>">
|
||||||
|
<?= $mail['due_date'] ?>
|
||||||
|
</small>
|
||||||
|
<?php else: ?>
|
||||||
|
<small class="text-muted">-</small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
<td><?= htmlspecialchars($mail['sender'] ?: $mail['recipient']) ?></td>
|
<td><?= htmlspecialchars($mail['sender'] ?: $mail['recipient']) ?></td>
|
||||||
<td><?= getStatusBadge($mail['status']) ?></td>
|
<td>
|
||||||
|
<?php if ($mail['assigned_to_name']): ?>
|
||||||
|
<small><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></small>
|
||||||
|
<?php else: ?>
|
||||||
|
<small class="text-muted">غير معين</small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= getStatusBadge($mail) ?></td>
|
||||||
<td class="pe-4 text-center"><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
<td class="pe-4 text-center"><?= date('Y-m-d', strtotime($mail['date_registered'])) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center py-4 text-muted">لا يوجد بريد مسجل حالياً</td>
|
<td colspan="8" class="text-center py-4 text-muted">لا يوجد بريد مسجل حالياً</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -127,4 +269,4 @@ function getStatusBadge($status) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
@ -14,30 +14,37 @@ class MailService
|
|||||||
{
|
{
|
||||||
$cfg = self::loadConfig();
|
$cfg = self::loadConfig();
|
||||||
|
|
||||||
|
// Check if enabled (db-backed settings)
|
||||||
|
if (isset($cfg['is_enabled']) && !$cfg['is_enabled']) {
|
||||||
|
self::logEmail($to, $subject, 'failure', 'SMTP is currently disabled due to repeated failures.');
|
||||||
|
return [ 'success' => false, 'error' => 'SMTP is disabled' ];
|
||||||
|
}
|
||||||
|
|
||||||
$autoload = __DIR__ . '/../vendor/autoload.php';
|
$autoload = __DIR__ . '/../vendor/autoload.php';
|
||||||
if (file_exists($autoload)) {
|
if (file_exists($autoload)) {
|
||||||
require_once $autoload;
|
require_once $autoload;
|
||||||
}
|
}
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
@require_once 'libphp-phpmailer/autoload.php';
|
@require_once 'libphp-phpmailer/autoload.php';
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
@require_once 'libphp-phpmailer/src/Exception.php';
|
@require_once 'libphp-phpmailer/src/Exception.php';
|
||||||
@require_once 'libphp-phpmailer/src/SMTP.php';
|
@require_once 'libphp-phpmailer/src/SMTP.php';
|
||||||
@require_once 'libphp-phpmailer/src/PHPMailer.php';
|
@require_once 'libphp-phpmailer/src/PHPMailer.php';
|
||||||
}
|
}
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
@require_once 'PHPMailer/src/Exception.php';
|
@require_once 'PHPMailer/src/Exception.php';
|
||||||
@require_once 'PHPMailer/src/SMTP.php';
|
@require_once 'PHPMailer/src/SMTP.php';
|
||||||
@require_once 'PHPMailer/src/PHPMailer.php';
|
@require_once 'PHPMailer/src/PHPMailer.php';
|
||||||
}
|
}
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
@require_once 'PHPMailer/Exception.php';
|
@require_once 'PHPMailer/Exception.php';
|
||||||
@require_once 'PHPMailer/SMTP.php';
|
@require_once 'PHPMailer/SMTP.php';
|
||||||
@require_once 'PHPMailer/PHPMailer.php';
|
@require_once 'PHPMailer/PHPMailer.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||||
|
self::logEmail($to, $subject, 'failure', 'PHPMailer not available');
|
||||||
return [ 'success' => false, 'error' => 'PHPMailer not available' ];
|
return [ 'success' => false, 'error' => 'PHPMailer not available' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +83,7 @@ class MailService
|
|||||||
if (filter_var($addr, FILTER_VALIDATE_EMAIL)) { $mail->addAddress($addr); $added++; }
|
if (filter_var($addr, FILTER_VALIDATE_EMAIL)) { $mail->addAddress($addr); $added++; }
|
||||||
}
|
}
|
||||||
if ($added === 0) {
|
if ($added === 0) {
|
||||||
|
self::logEmail($to, $subject, 'failure', 'No recipients defined');
|
||||||
return [ 'success' => false, 'error' => 'No recipients defined (set MAIL_TO or pass $to)' ];
|
return [ 'success' => false, 'error' => 'No recipients defined (set MAIL_TO or pass $to)' ];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,142 +102,86 @@ class MailService
|
|||||||
$mail->Body = $htmlBody;
|
$mail->Body = $htmlBody;
|
||||||
$mail->AltBody = $textBody ?? strip_tags($htmlBody);
|
$mail->AltBody = $textBody ?? strip_tags($htmlBody);
|
||||||
$ok = $mail->send();
|
$ok = $mail->send();
|
||||||
|
|
||||||
|
self::logEmail($to, $subject, 'success');
|
||||||
|
self::resetFailures();
|
||||||
|
|
||||||
return [ 'success' => $ok ];
|
return [ 'success' => $ok ];
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return [ 'success' => false, 'error' => 'PHPMailer error: ' . $e->getMessage() ];
|
$error = $e->getMessage();
|
||||||
|
self::logEmail($to, $subject, 'failure', $error);
|
||||||
|
self::incrementFailures();
|
||||||
|
return [ 'success' => false, 'error' => 'PHPMailer error: ' . $error ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function loadConfig(): array
|
private static function loadConfig(): array
|
||||||
{
|
{
|
||||||
$configPath = __DIR__ . '/config.php';
|
$configPath = __DIR__ . '/config.php';
|
||||||
if (!file_exists($configPath)) {
|
if (!file_exists($configPath)) {
|
||||||
throw new \RuntimeException('Mail config not found. Copy mail/config.sample.php to mail/config.php and fill in credentials.');
|
throw new \RuntimeException('Mail config not found.');
|
||||||
}
|
}
|
||||||
$cfg = require $configPath;
|
$cfg = require $configPath;
|
||||||
if (!is_array($cfg)) {
|
if (!is_array($cfg)) {
|
||||||
throw new \RuntimeException('Invalid mail config format: expected array');
|
throw new \RuntimeException('Invalid mail config format.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to load extra from DB
|
||||||
|
try {
|
||||||
|
$stmt = db()->query("SELECT * FROM smtp_settings LIMIT 1");
|
||||||
|
$dbCfg = $stmt->fetch();
|
||||||
|
if ($dbCfg) {
|
||||||
|
// Merge DB settings if not set in config or env
|
||||||
|
foreach ($dbCfg as $key => $val) {
|
||||||
|
if (!isset($cfg[$key])) $cfg[$key] = $val;
|
||||||
|
}
|
||||||
|
// Specifically override enablement
|
||||||
|
$cfg['is_enabled'] = (bool)$dbCfg['is_enabled'];
|
||||||
|
$cfg['max_failures'] = (int)$dbCfg['max_failures'];
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
|
||||||
return $cfg;
|
return $cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function logEmail($to, $subject, $status, $error = null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (is_array($to)) $to = implode(', ', $to);
|
||||||
|
$stmt = db()->prepare("INSERT INTO email_logs (recipient, subject, status, error_message) VALUES (?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$to, $subject, $status, $error]);
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function incrementFailures()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
db()->query("UPDATE smtp_settings SET consecutive_failures = consecutive_failures + 1 WHERE id = 1");
|
||||||
|
// Check if threshold reached
|
||||||
|
$stmt = db()->query("SELECT consecutive_failures, max_failures FROM smtp_settings WHERE id = 1");
|
||||||
|
$res = $stmt->fetch();
|
||||||
|
if ($res && $res['consecutive_failures'] >= $res['max_failures']) {
|
||||||
|
db()->query("UPDATE smtp_settings SET is_enabled = 0 WHERE id = 1");
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function resetFailures()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
db()->query("UPDATE smtp_settings SET consecutive_failures = 0 WHERE id = 1");
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
}
|
||||||
|
|
||||||
// Send a contact message
|
// Send a contact message
|
||||||
// $to can be: a single email string, a comma-separated list, an array of emails, or null (fallback to MAIL_TO/MAIL_FROM)
|
|
||||||
public static function sendContactMessage(string $name, string $email, string $message, $to = null, string $subject = 'New contact form')
|
public static function sendContactMessage(string $name, string $email, string $message, $to = null, string $subject = 'New contact form')
|
||||||
{
|
{
|
||||||
$cfg = self::loadConfig();
|
// For simplicity, let's just use sendMail for everything
|
||||||
|
$safeName = htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||||
// Try Composer autoload if available (for PHPMailer)
|
$safeEmail = htmlspecialchars($email, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
||||||
$autoload = __DIR__ . '/../vendor/autoload.php';
|
$safeBody = nl2br(htmlspecialchars($message, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
|
||||||
if (file_exists($autoload)) {
|
$html = "<p><strong>Name:</strong> {$safeName}</p><p><strong>Email:</strong> {$safeEmail}</p><hr>{$safeBody}";
|
||||||
require_once $autoload;
|
|
||||||
}
|
return self::sendMail($to, $subject, $html, $message, ['reply_to' => $email]);
|
||||||
// Fallback to system-wide PHPMailer (installed via apt: libphp-phpmailer)
|
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
|
||||||
// Debian/Ubuntu package layout (libphp-phpmailer)
|
|
||||||
@require_once 'libphp-phpmailer/autoload.php';
|
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
|
||||||
@require_once 'libphp-phpmailer/src/Exception.php';
|
|
||||||
@require_once 'libphp-phpmailer/src/SMTP.php';
|
|
||||||
@require_once 'libphp-phpmailer/src/PHPMailer.php';
|
|
||||||
}
|
|
||||||
// Alternative layout (older PHPMailer package names)
|
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
|
||||||
@require_once 'PHPMailer/src/Exception.php';
|
|
||||||
@require_once 'PHPMailer/src/SMTP.php';
|
|
||||||
@require_once 'PHPMailer/src/PHPMailer.php';
|
|
||||||
}
|
|
||||||
if (!class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
|
||||||
@require_once 'PHPMailer/Exception.php';
|
|
||||||
@require_once 'PHPMailer/SMTP.php';
|
|
||||||
@require_once 'PHPMailer/PHPMailer.php';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$transport = $cfg['transport'] ?? 'smtp';
|
|
||||||
if ($transport === 'smtp' && class_exists('PHPMailer\\PHPMailer\\PHPMailer')) {
|
|
||||||
return self::sendViaPHPMailer($cfg, $name, $email, $message, $to, $subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: attempt native mail() — works only if MTA is configured on the VM
|
|
||||||
return self::sendViaNativeMail($cfg, $name, $email, $message, $to, $subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function sendViaPHPMailer(array $cfg, string $name, string $email, string $body, $to, string $subject)
|
|
||||||
{
|
|
||||||
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
|
|
||||||
try {
|
|
||||||
$mail->isSMTP();
|
|
||||||
$mail->Host = $cfg['smtp_host'] ?? '';
|
|
||||||
$mail->Port = (int)($cfg['smtp_port'] ?? 587);
|
|
||||||
$secure = $cfg['smtp_secure'] ?? 'tls';
|
|
||||||
if ($secure === 'ssl') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
|
|
||||||
elseif ($secure === 'tls') $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
|
|
||||||
else $mail->SMTPSecure = false;
|
|
||||||
$mail->SMTPAuth = true;
|
|
||||||
$mail->Username = $cfg['smtp_user'] ?? '';
|
|
||||||
$mail->Password = $cfg['smtp_pass'] ?? '';
|
|
||||||
|
|
||||||
$fromEmail = $cfg['from_email'] ?? 'no-reply@localhost';
|
|
||||||
$fromName = $cfg['from_name'] ?? 'App';
|
|
||||||
$mail->setFrom($fromEmail, $fromName);
|
|
||||||
|
|
||||||
// Use Reply-To for the user's email to avoid spoofing From
|
|
||||||
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$mail->addReplyTo($email, $name ?: $email);
|
|
||||||
}
|
|
||||||
if (!empty($cfg['reply_to'])) {
|
|
||||||
$mail->addReplyTo($cfg['reply_to']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination: prefer dynamic recipients ($to), fallback to MAIL_TO; no silent FROM fallback
|
|
||||||
$toList = [];
|
|
||||||
if ($to) {
|
|
||||||
if (is_string($to)) {
|
|
||||||
// allow comma-separated list
|
|
||||||
$toList = array_map('trim', explode(',', $to));
|
|
||||||
} elseif (is_array($to)) {
|
|
||||||
$toList = $to;
|
|
||||||
}
|
|
||||||
} elseif (!empty(getenv('MAIL_TO'))) {
|
|
||||||
$toList = array_map('trim', explode(',', getenv('MAIL_TO')));
|
|
||||||
}
|
|
||||||
$added = 0;
|
|
||||||
foreach ($toList as $addr) {
|
|
||||||
if (filter_var($addr, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$mail->addAddress($addr);
|
|
||||||
$added++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($added === 0) {
|
|
||||||
return [ 'success' => false, 'error' => 'No recipients defined (set MAIL_TO or pass $to)' ];
|
|
||||||
}
|
|
||||||
|
|
||||||
// DKIM (optional)
|
|
||||||
if (!empty($cfg['dkim_domain']) && !empty($cfg['dkim_selector']) && !empty($cfg['dkim_private_key_path'])) {
|
|
||||||
$mail->DKIM_domain = $cfg['dkim_domain'];
|
|
||||||
$mail->DKIM_selector = $cfg['dkim_selector'];
|
|
||||||
$mail->DKIM_private = $cfg['dkim_private_key_path'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$mail->isHTML(true);
|
|
||||||
$mail->Subject = $subject;
|
|
||||||
$safeName = htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
||||||
$safeEmail = htmlspecialchars($email, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
||||||
$safeBody = nl2br(htmlspecialchars($body, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
|
|
||||||
$mail->Body = "<p><strong>Name:</strong> {$safeName}</p><p><strong>Email:</strong> {$safeEmail}</p><hr>{$safeBody}";
|
|
||||||
$mail->AltBody = "Name: {$name}\nEmail: {$email}\n\n{$body}";
|
|
||||||
|
|
||||||
$ok = $mail->send();
|
|
||||||
return [ 'success' => $ok ];
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return [ 'success' => false, 'error' => 'PHPMailer error: ' . $e->getMessage() ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function sendViaNativeMail(array $cfg, string $name, string $email, string $body, $to, string $subject)
|
|
||||||
{
|
|
||||||
$opts = ['reply_to' => $email];
|
|
||||||
$html = nl2br(htmlspecialchars($body, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
|
|
||||||
return self::sendMail($to, $subject, $html, $body, $opts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,76 +1,71 @@
|
|||||||
<?php
|
<?php
|
||||||
// Mail configuration sourced from environment variables.
|
// Mail configuration sourced from environment variables or database.
|
||||||
// No secrets are stored here; the file just maps env -> config array for MailService.
|
|
||||||
|
|
||||||
function env_val(string $key, $default = null) {
|
if (!function_exists('env_val')) {
|
||||||
$v = getenv($key);
|
function env_val(string $key, $default = null) {
|
||||||
return ($v === false || $v === null || $v === '') ? $default : $v;
|
$v = getenv($key);
|
||||||
|
return ($v === false || $v === null || $v === '') ? $default : $v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: if critical vars are missing from process env, try to parse executor/.env
|
// Fallback: if critical vars are missing from process env, try to parse executor/.env
|
||||||
// This helps in web/Apache contexts where .env is not exported.
|
if (!function_exists('load_dotenv_if_needed')) {
|
||||||
// Supports simple KEY=VALUE lines; ignores quotes and comments.
|
function load_dotenv_if_needed(array $keys): void {
|
||||||
function load_dotenv_if_needed(array $keys): void {
|
$missing = array_filter($keys, fn($k) => getenv($k) === false || getenv($k) === '');
|
||||||
$missing = array_filter($keys, fn($k) => getenv($k) === false || getenv($k) === '');
|
if (empty($missing)) return;
|
||||||
if (empty($missing)) return;
|
static $loaded = false;
|
||||||
static $loaded = false;
|
if ($loaded) return;
|
||||||
if ($loaded) return;
|
$envPath = realpath(__DIR__ . '/../../.env'); // executor/.env
|
||||||
$envPath = realpath(__DIR__ . '/../../.env'); // executor/.env
|
if ($envPath && is_readable($envPath)) {
|
||||||
if ($envPath && is_readable($envPath)) {
|
$lines = @file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
||||||
$lines = @file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [];
|
foreach ($lines as $line) {
|
||||||
foreach ($lines as $line) {
|
if ($line[0] === '#' || trim($line) === '') continue;
|
||||||
if ($line[0] === '#' || trim($line) === '') continue;
|
if (!str_contains($line, '=')) continue;
|
||||||
if (!str_contains($line, '=')) continue;
|
[$k, $v] = array_map('trim', explode('=', $line, 2));
|
||||||
[$k, $v] = array_map('trim', explode('=', $line, 2));
|
$v = trim($v, "' ");
|
||||||
// Strip potential surrounding quotes
|
if ($k !== '' && (getenv($k) === false || getenv($k) === '')) {
|
||||||
$v = trim($v, "\"' ");
|
putenv("{$k}={$v}");
|
||||||
// Do not override existing env
|
}
|
||||||
if ($k !== '' && (getenv($k) === false || getenv($k) === '')) {
|
|
||||||
putenv("{$k}={$v}");
|
|
||||||
}
|
}
|
||||||
|
$loaded = true;
|
||||||
}
|
}
|
||||||
$loaded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
load_dotenv_if_needed([
|
load_dotenv_if_needed([
|
||||||
'MAIL_TRANSPORT','SMTP_HOST','SMTP_PORT','SMTP_SECURE','SMTP_USER','SMTP_PASS',
|
'MAIL_TRANSPORT','SMTP_HOST','SMTP_PORT','SMTP_SECURE','SMTP_USER','SMTP_PASS',
|
||||||
'MAIL_FROM','MAIL_FROM_NAME','MAIL_REPLY_TO','MAIL_TO',
|
'MAIL_FROM','MAIL_FROM_NAME','MAIL_REPLY_TO','MAIL_TO'
|
||||||
'DKIM_DOMAIN','DKIM_SELECTOR','DKIM_PRIVATE_KEY_PATH'
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$transport = env_val('MAIL_TRANSPORT', 'smtp');
|
// Fetch from DB if available
|
||||||
$smtp_host = env_val('SMTP_HOST');
|
$db_settings = [];
|
||||||
$smtp_port = (int) env_val('SMTP_PORT', 587);
|
try {
|
||||||
$smtp_secure = env_val('SMTP_SECURE', 'tls'); // tls | ssl | null
|
require_once __DIR__ . '/../db/config.php';
|
||||||
$smtp_user = env_val('SMTP_USER');
|
$stmt = db()->query("SELECT * FROM smtp_settings WHERE id = 1");
|
||||||
$smtp_pass = env_val('SMTP_PASS');
|
$db_settings = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// DB not ready or table missing
|
||||||
|
}
|
||||||
|
|
||||||
$from_email = env_val('MAIL_FROM', 'no-reply@localhost');
|
$transport = env_val('MAIL_TRANSPORT', $db_settings['transport'] ?? 'smtp');
|
||||||
$from_name = env_val('MAIL_FROM_NAME', 'App');
|
$smtp_host = env_val('SMTP_HOST', $db_settings['smtp_host'] ?? '');
|
||||||
$reply_to = env_val('MAIL_REPLY_TO');
|
$smtp_port = (int) env_val('SMTP_PORT', $db_settings['smtp_port'] ?? 587);
|
||||||
|
$smtp_secure = env_val('SMTP_SECURE', $db_settings['smtp_secure'] ?? 'tls');
|
||||||
|
$smtp_user = env_val('SMTP_USER', $db_settings['smtp_user'] ?? '');
|
||||||
|
$smtp_pass = env_val('SMTP_PASS', $db_settings['smtp_pass'] ?? '');
|
||||||
|
|
||||||
$dkim_domain = env_val('DKIM_DOMAIN');
|
$from_email = env_val('MAIL_FROM', $db_settings['from_email'] ?? 'no-reply@localhost');
|
||||||
$dkim_selector = env_val('DKIM_SELECTOR');
|
$from_name = env_val('MAIL_FROM_NAME', $db_settings['from_name'] ?? 'App');
|
||||||
$dkim_private_key_path = env_val('DKIM_PRIVATE_KEY_PATH');
|
$reply_to = env_val('MAIL_REPLY_TO', $db_settings['reply_to'] ?? '');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'transport' => $transport,
|
'transport' => $transport,
|
||||||
|
|
||||||
// SMTP
|
|
||||||
'smtp_host' => $smtp_host,
|
'smtp_host' => $smtp_host,
|
||||||
'smtp_port' => $smtp_port,
|
'smtp_port' => $smtp_port,
|
||||||
'smtp_secure' => $smtp_secure,
|
'smtp_secure' => $smtp_secure,
|
||||||
'smtp_user' => $smtp_user,
|
'smtp_user' => $smtp_user,
|
||||||
'smtp_pass' => $smtp_pass,
|
'smtp_pass' => $smtp_pass,
|
||||||
|
|
||||||
// From / Reply-To
|
|
||||||
'from_email' => $from_email,
|
'from_email' => $from_email,
|
||||||
'from_name' => $from_name,
|
'from_name' => $from_name,
|
||||||
'reply_to' => $reply_to,
|
'reply_to' => $reply_to,
|
||||||
|
];
|
||||||
// DKIM (optional)
|
|
||||||
'dkim_domain' => $dkim_domain,
|
|
||||||
'dkim_selector' => $dkim_selector,
|
|
||||||
'dkim_private_key_path' => $dkim_private_key_path,
|
|
||||||
];
|
|
||||||
198
outbound.php
198
outbound.php
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/mail/MailService.php';
|
||||||
|
|
||||||
// Safe truncation helper
|
// Safe truncation helper
|
||||||
if (!function_exists('truncate_text')) {
|
if (!function_exists('truncate_text')) {
|
||||||
@ -15,6 +16,45 @@ if (!function_exists('truncate_text')) {
|
|||||||
|
|
||||||
$error = '';
|
$error = '';
|
||||||
$success = '';
|
$success = '';
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
|
||||||
|
// Fetch statuses
|
||||||
|
$statuses_list = db()->query("SELECT * FROM mailbox_statuses ORDER BY id ASC")->fetchAll();
|
||||||
|
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
||||||
|
|
||||||
|
// Function to send assignment notification
|
||||||
|
function sendAssignmentNotification($assigned_to_id, $ref_no, $subject) {
|
||||||
|
if (!$assigned_to_id) return;
|
||||||
|
|
||||||
|
$stmt = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$assigned_to_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user && !empty($user['email'])) {
|
||||||
|
$to = $user['email'];
|
||||||
|
$email_subject = "تنبيه: تم تعيين بريد جديد لك (رقم القيد: $ref_no)";
|
||||||
|
$htmlBody = "
|
||||||
|
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
||||||
|
<h2>مرحباً " . htmlspecialchars($user['full_name']) . "</h2>
|
||||||
|
<p>لقد تم تعيين مهمة بريد جديد لك في النظام.</p>
|
||||||
|
<table border='1' cellpadding='10' cellspacing='0' style='border-collapse: collapse;'>
|
||||||
|
<tr>
|
||||||
|
<th style='background-color: #f8f9fa;'>رقم القيد</th>
|
||||||
|
<td>" . htmlspecialchars($ref_no) . "</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style='background-color: #f8f9fa;'>الموضوع</th>
|
||||||
|
<td>" . htmlspecialchars($subject) . "</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p>يرجى الدخول للنظام لمتابعة المهمة.</p>
|
||||||
|
<br>
|
||||||
|
<p>هذا تنبيه تلقائي، يرجى عدم الرد.</p>
|
||||||
|
</div>
|
||||||
|
";
|
||||||
|
MailService::sendMail($to, $email_subject, $htmlBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle actions
|
// Handle actions
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
@ -22,11 +62,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$type = 'outbound';
|
$type = 'outbound';
|
||||||
$ref_no = $_POST['ref_no'] ?? '';
|
$ref_no = $_POST['ref_no'] ?? '';
|
||||||
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
$date_registered = $_POST['date_registered'] ?? date('Y-m-d');
|
||||||
|
$due_date = !empty($_POST['due_date']) ? $_POST['due_date'] : null;
|
||||||
$sender = $_POST['sender'] ?? '';
|
$sender = $_POST['sender'] ?? '';
|
||||||
$recipient = $_POST['recipient'] ?? '';
|
$recipient = $_POST['recipient'] ?? '';
|
||||||
$subject = $_POST['subject'] ?? '';
|
$subject = $_POST['subject'] ?? '';
|
||||||
$description = $_POST['description'] ?? '';
|
$description = $_POST['description'] ?? '';
|
||||||
$status = $_POST['status'] ?? 'received';
|
$status_id = $_POST['status_id'] ?? $default_status_id;
|
||||||
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
$assigned_to = !empty($_POST['assigned_to']) ? $_POST['assigned_to'] : null;
|
||||||
$id = $_POST['id'] ?? 0;
|
$id = $_POST['id'] ?? 0;
|
||||||
|
|
||||||
@ -34,14 +75,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
try {
|
try {
|
||||||
db()->beginTransaction();
|
db()->beginTransaction();
|
||||||
if ($action === 'add') {
|
if ($action === 'add') {
|
||||||
$stmt = db()->prepare("INSERT INTO mailbox (type, ref_no, date_registered, sender, recipient, subject, description, status, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
$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, $sender, $recipient, $subject, $description, $status, $assigned_to, $_SESSION['user_id']]);
|
$stmt->execute([$type, $ref_no, $date_registered, $due_date, $sender, $recipient, $subject, $description, $status_id, $assigned_to, $user_id]);
|
||||||
$mail_id = db()->lastInsertId();
|
$mail_id = db()->lastInsertId();
|
||||||
|
|
||||||
|
if ($assigned_to) {
|
||||||
|
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
$success = 'تمت إضافة البريد الصادر بنجاح';
|
$success = 'تمت إضافة البريد الصادر بنجاح';
|
||||||
} elseif ($action === 'edit') {
|
} elseif ($action === 'edit') {
|
||||||
$mail_id = $id;
|
$mail_id = $id;
|
||||||
$stmt = db()->prepare("UPDATE mailbox SET ref_no = ?, date_registered = ?, sender = ?, recipient = ?, subject = ?, description = ?, status = ?, assigned_to = ? WHERE id = ? AND type = 'outbound'");
|
|
||||||
$stmt->execute([$ref_no, $date_registered, $sender, $recipient, $subject, $description, $status, $assigned_to, $mail_id]);
|
// Get previous assigned_to to check if it changed
|
||||||
|
$stmt_old = db()->prepare("SELECT assigned_to FROM mailbox 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->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) {
|
||||||
|
sendAssignmentNotification($assigned_to, $ref_no, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
$success = 'تم تحديث البيانات بنجاح';
|
$success = 'تم تحديث البيانات بنجاح';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +112,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$file_name = time() . '_' . basename($name);
|
$file_name = time() . '_' . basename($name);
|
||||||
$target_path = $upload_dir . $file_name;
|
$target_path = $upload_dir . $file_name;
|
||||||
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
||||||
// Default display_name to original name for multiple uploads
|
|
||||||
$stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
$stmt = db()->prepare("INSERT INTO attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
||||||
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
||||||
}
|
}
|
||||||
@ -86,13 +142,28 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
$query = "SELECT * FROM mailbox WHERE type = 'outbound'";
|
$my_tasks = isset($_GET['my_tasks']) && $_GET['my_tasks'] == 1;
|
||||||
|
|
||||||
|
$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 = 'outbound'";
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$query .= " AND (ref_no LIKE ? OR recipient LIKE ? OR subject LIKE ?)";
|
$query .= " AND (m.ref_no LIKE ? OR m.recipient LIKE ? OR m.subject LIKE ?)";
|
||||||
$params = ["%$search%", "%$search%", "%$search%"];
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
}
|
}
|
||||||
$query .= " ORDER BY created_at DESC";
|
|
||||||
|
if ($my_tasks) {
|
||||||
|
$query .= " AND m.assigned_to = ?";
|
||||||
|
$params[] = $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= " ORDER BY m.created_at DESC";
|
||||||
$stmt = db()->prepare($query);
|
$stmt = db()->prepare($query);
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
$mails = $stmt->fetchAll();
|
$mails = $stmt->fetchAll();
|
||||||
@ -106,6 +177,19 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
$stmt->execute([$_GET['id']]);
|
$stmt->execute([$_GET['id']]);
|
||||||
$deepLinkData = $stmt->fetch();
|
$deepLinkData = $stmt->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStatusBadgeInList($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 = 'قيد المعالجة';
|
||||||
|
if ($status_name == 'closed') $display_name = 'مكتمل';
|
||||||
|
|
||||||
|
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
@ -131,13 +215,24 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
|
|
||||||
<div class="card shadow-sm border-0 mb-4">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<div class="card-header bg-white py-3">
|
<div class="card-header bg-white py-3">
|
||||||
<form class="row g-2">
|
<form class="row g-3 align-items-center">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المستلم..." value="<?= htmlspecialchars($search) ?>">
|
<input type="text" name="search" class="form-control" placeholder="بحث برقم القيد أو الموضوع أو المستلم..." value="<?= htmlspecialchars($search) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-md-3">
|
||||||
<button type="submit" class="btn btn-secondary">بحث</button>
|
<div class="form-check form-switch mt-1">
|
||||||
|
<input class="form-check-input" type="checkbox" name="my_tasks" id="myTasksSwitch" value="1" <?= $my_tasks ? 'checked' : '' ?> onchange="this.form.submit()">
|
||||||
|
<label class="form-check-label fw-bold" for="myTasksSwitch">مهامي فقط</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="submit" class="btn btn-secondary px-4">بحث</button>
|
||||||
|
</div>
|
||||||
|
<?php if ($search || $my_tasks): ?>
|
||||||
|
<div class="col-auto">
|
||||||
|
<a href="outbound.php" class="btn btn-link text-decoration-none">إلغاء التصفية</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
@ -147,8 +242,10 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="ps-4">رقم القيد</th>
|
<th class="ps-4">رقم القيد</th>
|
||||||
<th>التاريخ</th>
|
<th>التاريخ</th>
|
||||||
|
<th>الموعد النهائي</th>
|
||||||
<th>الموضوع</th>
|
<th>الموضوع</th>
|
||||||
<th>المستلم الخارجى</th>
|
<th>المستلم</th>
|
||||||
|
<th>المسؤول</th>
|
||||||
<th>الحالة</th>
|
<th>الحالة</th>
|
||||||
<th class="pe-4 text-center">الإجراءات</th>
|
<th class="pe-4 text-center">الإجراءات</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -158,21 +255,32 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||||
<td><?= $mail['date_registered'] ?></td>
|
<td><?= $mail['date_registered'] ?></td>
|
||||||
<td><?= truncate_text($mail['subject'], 100) ?></td>
|
|
||||||
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
|
||||||
<td>
|
<td>
|
||||||
<?php if ($mail['status'] === 'received'): ?>
|
<?php if ($mail['due_date']): ?>
|
||||||
<span class="badge bg-secondary">تم الاستلام</span>
|
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : '' ?>">
|
||||||
<?php elseif ($mail['status'] === 'in_progress'): ?>
|
<?= $mail['due_date'] ?>
|
||||||
<span class="badge bg-info text-dark">قيد المعالجة</span>
|
<?php if (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed'): ?>
|
||||||
<?php elseif ($mail['status'] === 'closed'): ?>
|
<i class="fas fa-exclamation-triangle ms-1"></i>
|
||||||
<span class="badge bg-success">مكتمل</span>
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
|
<td><?= truncate_text($mail['subject'], 80) ?></td>
|
||||||
|
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($mail['assigned_to_name']): ?>
|
||||||
|
<span class="text-nowrap"><i class="fas fa-user-tag me-1 text-muted"></i> <?= htmlspecialchars($mail['assigned_to_name']) ?></span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">غير معين</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= getStatusBadgeInList($mail) ?></td>
|
||||||
<td class="pe-4 text-center">
|
<td class="pe-4 text-center">
|
||||||
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-outline-info" title="عرض التفاصيل"><i class="fas fa-eye"></i></a>
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||||
onclick="openMailModal('edit', <?= htmlspecialchars(json_encode($mail), ENT_QUOTES, 'UTF-8') ?>)" title="تعديل">
|
onclick='openMailModal("edit", <?= json_encode($mail) ?>)' title="تعديل">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
<a href="javascript:void(0)" onclick="confirmDelete(<?= $mail['id'] ?>)" class="btn btn-sm btn-outline-danger" title="حذف"><i class="fas fa-trash"></i></a>
|
||||||
@ -180,7 +288,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; else: ?>
|
<?php endforeach; else: ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="text-center py-4 text-muted">لا يوجد بريد صادر مسجل حالياً</td>
|
<td colspan="8" class="text-center py-4 text-muted">لا يوجد بريد صادر مسجل حالياً</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -203,14 +311,18 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<input type="hidden" name="id" id="modalId" value="0">
|
<input type="hidden" name="id" id="modalId" value="0">
|
||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">رقم القيد <span class="text-danger">*</span></label>
|
||||||
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required>
|
<input type="text" name="ref_no" id="modalRefNo" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-4">
|
||||||
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
<label class="form-label fw-bold">تاريخ التسجيل</label>
|
||||||
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
<input type="date" name="date_registered" id="modalDateRegistered" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-bold">الموعد النهائي</label>
|
||||||
|
<input type="date" name="due_date" id="modalDueDate" class="form-control">
|
||||||
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label fw-bold">المستلم الخارجي (الجهة المستلمة)</label>
|
<label class="form-label fw-bold">المستلم الخارجي (الجهة المستلمة)</label>
|
||||||
<input type="text" name="recipient" id="modalRecipient" class="form-control">
|
<input type="text" name="recipient" id="modalRecipient" class="form-control">
|
||||||
@ -230,14 +342,19 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label fw-bold">المرفقات</label>
|
<label class="form-label fw-bold">المرفقات</label>
|
||||||
<input type="file" name="attachments[]" class="form-control" multiple>
|
<input type="file" name="attachments[]" class="form-control" multiple>
|
||||||
<div class="form-text text-muted">يمكنك اختيار ملفات متعددة.</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label fw-bold">الحالة</label>
|
<label class="form-label fw-bold">الحالة</label>
|
||||||
<select name="status" id="modalStatus" class="form-select">
|
<select name="status_id" id="modalStatusId" class="form-select">
|
||||||
<option value="received">تم الاستلام</option>
|
<?php foreach ($statuses_list as $s): ?>
|
||||||
<option value="in_progress">قيد المعالجة</option>
|
<?php
|
||||||
<option value="closed">مكتمل / مغلق</option>
|
$d_name = $s['name'];
|
||||||
|
if ($d_name == 'received') $d_name = 'تم الاستلام';
|
||||||
|
if ($d_name == 'in_progress') $d_name = 'قيد المعالجة';
|
||||||
|
if ($d_name == 'closed') $d_name = 'مكتمل / مغلق';
|
||||||
|
?>
|
||||||
|
<option value="<?= $s['id'] ?>"><?= htmlspecialchars($d_name) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -299,10 +416,11 @@ function openMailModal(action, data = null) {
|
|||||||
const fields = {
|
const fields = {
|
||||||
ref_no: document.getElementById('modalRefNo'),
|
ref_no: document.getElementById('modalRefNo'),
|
||||||
date_registered: document.getElementById('modalDateRegistered'),
|
date_registered: document.getElementById('modalDateRegistered'),
|
||||||
|
due_date: document.getElementById('modalDueDate'),
|
||||||
sender: document.getElementById('modalSender'),
|
sender: document.getElementById('modalSender'),
|
||||||
recipient: document.getElementById('modalRecipient'),
|
recipient: document.getElementById('modalRecipient'),
|
||||||
subject: document.getElementById('modalSubject'),
|
subject: document.getElementById('modalSubject'),
|
||||||
status: document.getElementById('modalStatus'),
|
status_id: document.getElementById('modalStatusId'),
|
||||||
assigned_to: document.getElementById('modalAssignedTo')
|
assigned_to: document.getElementById('modalAssignedTo')
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -314,7 +432,7 @@ function openMailModal(action, data = null) {
|
|||||||
Object.keys(fields).forEach(key => {
|
Object.keys(fields).forEach(key => {
|
||||||
if (fields[key]) {
|
if (fields[key]) {
|
||||||
if (key === 'date_registered') fields[key].value = '<?= date('Y-m-d') ?>';
|
if (key === 'date_registered') fields[key].value = '<?= date('Y-m-d') ?>';
|
||||||
else if (key === 'status') fields[key].value = 'received';
|
else if (key === 'status_id') fields[key].value = '<?= $default_status_id ?>';
|
||||||
else fields[key].value = '';
|
else fields[key].value = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -337,7 +455,6 @@ function openMailModal(action, data = null) {
|
|||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
initEditors().finally(() => {
|
initEditors().finally(() => {
|
||||||
// Deep link or error handling
|
|
||||||
<?php if ($deepLinkData): ?>
|
<?php if ($deepLinkData): ?>
|
||||||
openMailModal('edit', <?= json_encode($deepLinkData) ?>);
|
openMailModal('edit', <?= json_encode($deepLinkData) ?>);
|
||||||
<?php elseif ($error && isset($_POST['action'])): ?>
|
<?php elseif ($error && isset($_POST['action'])): ?>
|
||||||
@ -345,11 +462,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
'id' => $_POST['id'] ?? 0,
|
'id' => $_POST['id'] ?? 0,
|
||||||
'ref_no' => $_POST['ref_no'] ?? '',
|
'ref_no' => $_POST['ref_no'] ?? '',
|
||||||
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
'date_registered' => $_POST['date_registered'] ?? date('Y-m-d'),
|
||||||
|
'due_date' => $_POST['due_date'] ?? '',
|
||||||
'sender' => $_POST['sender'] ?? '',
|
'sender' => $_POST['sender'] ?? '',
|
||||||
'recipient' => $_POST['recipient'] ?? '',
|
'recipient' => $_POST['recipient'] ?? '',
|
||||||
'subject' => $_POST['subject'] ?? '',
|
'subject' => $_POST['subject'] ?? '',
|
||||||
'description' => $_POST['description'] ?? '',
|
'description' => $_POST['description'] ?? '',
|
||||||
'status' => $_POST['status'] ?? 'received',
|
'status_id' => $_POST['status_id'] ?? $default_status_id,
|
||||||
'assigned_to' => $_POST['assigned_to'] ?? ''
|
'assigned_to' => $_POST['assigned_to'] ?? ''
|
||||||
]) ?>;
|
]) ?>;
|
||||||
openMailModal('<?= $_POST['action'] ?>', errorData);
|
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||||
@ -358,7 +476,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle form submission to ensure CKEditor data is synced
|
|
||||||
document.getElementById('mailForm').addEventListener('submit', function() {
|
document.getElementById('mailForm').addEventListener('submit', function() {
|
||||||
if (descriptionEditor) descriptionEditor.updateSourceElement();
|
if (descriptionEditor) descriptionEditor.updateSourceElement();
|
||||||
});
|
});
|
||||||
@ -396,16 +513,9 @@ function confirmDelete(id) {
|
|||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.modal-header {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.modal-footer {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
/* Specific styling for green header */
|
|
||||||
.modal-header.bg-success {
|
.modal-header.bg-success {
|
||||||
background-color: #198754 !important;
|
background-color: #198754 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
126
overdue_report.php
Normal file
126
overdue_report.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'includes/header.php';
|
||||||
|
|
||||||
|
if (!isAdmin()) {
|
||||||
|
redirect('index.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
$type_filter = $_GET['type'] ?? '';
|
||||||
|
$user_filter = $_GET['user_id'] ?? '';
|
||||||
|
|
||||||
|
$params = [];
|
||||||
|
$where = ["due_date < CURDATE()", "status != 'closed'"];
|
||||||
|
|
||||||
|
if ($type_filter) {
|
||||||
|
$where[] = "type = ?";
|
||||||
|
$params[] = $type_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user_filter) {
|
||||||
|
$where[] = "assigned_to = ?";
|
||||||
|
$params[] = $user_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
$where_clause = implode(" AND ", $where);
|
||||||
|
$sql = "SELECT m.*, u.full_name as assigned_name
|
||||||
|
FROM mailbox m
|
||||||
|
LEFT JOIN users u ON m.assigned_to = u.id
|
||||||
|
WHERE $where_clause
|
||||||
|
ORDER BY m.due_date ASC";
|
||||||
|
|
||||||
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
$overdue_items = $stmt->fetchAll();
|
||||||
|
|
||||||
|
// Fetch all users for filter
|
||||||
|
$users = db()->query("SELECT id, full_name FROM users ORDER BY full_name")->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h1 class="h2">تقرير المهام المتأخرة</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="GET" class="row g-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">نوع البريد</label>
|
||||||
|
<select name="type" class="form-select">
|
||||||
|
<option value="">الكل</option>
|
||||||
|
<option value="inbound" <?= $type_filter == 'inbound' ? 'selected' : '' ?>>وارد</option>
|
||||||
|
<option value="outbound" <?= $type_filter == 'outbound' ? 'selected' : '' ?>>صادر</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">الموظف المسؤول</label>
|
||||||
|
<select name="user_id" class="form-select">
|
||||||
|
<option value="">الكل</option>
|
||||||
|
<?php foreach ($users as $user): ?>
|
||||||
|
<option value="<?= $user['id'] ?>" <?= $user_filter == $user['id'] ? 'selected' : '' ?>>
|
||||||
|
<?= htmlspecialchars($user['full_name']) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 d-flex align-items-end">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">تصفية</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header bg-danger text-white">
|
||||||
|
<h5 class="card-title mb-0"><i class="fas fa-exclamation-triangle me-2"></i> جميع المهام المتأخرة</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>رقم المرجع</th>
|
||||||
|
<th>النوع</th>
|
||||||
|
<th>الموضوع</th>
|
||||||
|
<th>الموظف المسؤول</th>
|
||||||
|
<th>تاريخ الاستحقاق</th>
|
||||||
|
<th>الأيام المتأخرة</th>
|
||||||
|
<th>الإجراءات</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($overdue_items)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" class="text-center py-4 text-muted">لا توجد مهام متأخرة حالياً.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($overdue_items as $item):
|
||||||
|
$due_date = new DateTime($item['due_date']);
|
||||||
|
$today = new DateTime();
|
||||||
|
$diff = $today->diff($due_date)->format("%a");
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= htmlspecialchars($item['ref_no']) ?></td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-<?= $item['type'] == 'inbound' ? 'info' : 'warning' ?>">
|
||||||
|
<?= $item['type'] == 'inbound' ? 'وارد' : 'صادر' ?>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td><?= htmlspecialchars($item['subject']) ?></td>
|
||||||
|
<td><?= htmlspecialchars($item['assigned_name'] ?? 'غير معين') ?></td>
|
||||||
|
<td class="text-danger fw-bold"><?= $item['due_date'] ?></td>
|
||||||
|
<td class="text-danger fw-bold"><?= $diff ?> يوم</td>
|
||||||
|
<td>
|
||||||
|
<a href="view_mail.php?id=<?= $item['id'] ?>" class="btn btn-sm btn-outline-primary">
|
||||||
|
<i class="fas fa-eye"></i> عرض
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'includes/footer.php'; ?>
|
||||||
75
scripts/send_reminders.php
Normal file
75
scripts/send_reminders.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
// scripts/send_reminders.php
|
||||||
|
// Should be run as a cron job daily: php scripts/send_reminders.php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../db/config.php';
|
||||||
|
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
|
||||||
|
WHERE m.due_date = DATE_ADD(CURDATE(), INTERVAL 1 DAY)
|
||||||
|
AND m.status != 'closed'
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
foreach ($due_tomorrow as $task) {
|
||||||
|
if (!empty($task['email'])) {
|
||||||
|
$subject = "تذكير: موعد نهائي لمهمة غداً - " . $task['ref_no'];
|
||||||
|
$html = "
|
||||||
|
<h3>تذكير بموعد نهائي</h3>
|
||||||
|
<p>عزيزي <b>" . htmlspecialchars($task['full_name']) . "</b>،</p>
|
||||||
|
<p>هذا تذكير بأن المهمة التالية مستحقة غداً:</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>رقم المرجع:</b> " . htmlspecialchars($task['ref_no']) . "</li>
|
||||||
|
<li><b>الموضوع:</b> " . htmlspecialchars($task['subject']) . "</li>
|
||||||
|
<li><b>تاريخ الاستحقاق:</b> " . $task['due_date'] . "</li>
|
||||||
|
</ul>
|
||||||
|
<p>يرجى متابعة المهمة وإغلاقها في الوقت المحدد.</p>
|
||||||
|
";
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
WHERE m.due_date < CURDATE()
|
||||||
|
AND m.status != 'closed'
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
foreach ($overdue as $task) {
|
||||||
|
if (!empty($task['email'])) {
|
||||||
|
$subject = "تنبيه: مهمة متأخرة! - " . $task['ref_no'];
|
||||||
|
$html = "
|
||||||
|
<h3 style='color: red;'>تنبيه: مهمة متأخرة</h3>
|
||||||
|
<p>عزيزي <b>" . htmlspecialchars($task['full_name']) . "</b>،</p>
|
||||||
|
<p>هذه المهمة قد تجاوزت الموعد النهائي المحدد:</p>
|
||||||
|
<ul>
|
||||||
|
<li><b>رقم المرجع:</b> " . htmlspecialchars($task['ref_no']) . "</li>
|
||||||
|
<li><b>الموضوع:</b> " . htmlspecialchars($task['subject']) . "</li>
|
||||||
|
<li><b>تاريخ الاستحقاق:</b> <span style='color: red;'>" . $task['due_date'] . "</span></li>
|
||||||
|
</ul>
|
||||||
|
<p>يرجى معالجة هذه المهمة في أقرب وقت ممكن.</p>
|
||||||
|
";
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[" . date('Y-m-d H:i:s') . "] Reminder process finished." . PHP_EOL;
|
||||||
290
user_dashboard.php
Normal file
290
user_dashboard.php
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$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();
|
||||||
|
|
||||||
|
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE assigned_to = ? AND status != 'closed'");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$my_pending_tasks = $stmt->fetchColumn();
|
||||||
|
|
||||||
|
// Global Stats (for Clerks or if we want to show them)
|
||||||
|
$total_inbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'inbound'")->fetchColumn();
|
||||||
|
$total_outbound = db()->query("SELECT COUNT(*) FROM mailbox WHERE type = 'outbound'")->fetchColumn();
|
||||||
|
|
||||||
|
// Fetch statuses for badge and count
|
||||||
|
$statuses_data = db()->query("SELECT * FROM mailbox_statuses")->fetchAll(PDO::FETCH_UNIQUE);
|
||||||
|
|
||||||
|
// My Assignments
|
||||||
|
$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 = ?
|
||||||
|
ORDER BY m.created_at DESC LIMIT 10");
|
||||||
|
$my_assignments->execute([$user_id]);
|
||||||
|
$my_assignments = $my_assignments->fetchAll();
|
||||||
|
|
||||||
|
// Recent Activity
|
||||||
|
$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";
|
||||||
|
|
||||||
|
if ($is_clerk) {
|
||||||
|
// Clerks see all recent activity
|
||||||
|
$recent_stmt = db()->prepare($recent_query . " ORDER BY m.updated_at DESC LIMIT 10");
|
||||||
|
$recent_stmt->execute();
|
||||||
|
} else {
|
||||||
|
// Staff see only theirs
|
||||||
|
$recent_stmt = db()->prepare($recent_query . " WHERE m.assigned_to = ? OR m.created_by = ? ORDER BY m.updated_at DESC LIMIT 10");
|
||||||
|
$recent_stmt->execute([$user_id, $user_id]);
|
||||||
|
}
|
||||||
|
$recent_activity = $recent_stmt->fetchAll();
|
||||||
|
|
||||||
|
function getStatusBadge($mail) {
|
||||||
|
$status_name = $mail['status_name'] ?? 'غير معروف';
|
||||||
|
$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 '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card bg-dark text-white p-4 shadow-lg border-0 overflow-hidden position-relative">
|
||||||
|
<div class="position-absolute end-0 top-0 p-3 opacity-10">
|
||||||
|
<i class="fas fa-envelope-open-text fa-10x" style="transform: rotate(-15deg);"></i>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between align-items-center position-relative">
|
||||||
|
<div>
|
||||||
|
<h2 class="fw-bold mb-1">مرحباً، <?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['username']) ?>!</h2>
|
||||||
|
<p class="mb-0 opacity-75">
|
||||||
|
<?php if ($is_clerk): ?>
|
||||||
|
أنت مسجل كـ <strong>كاتب</strong>. يمكنك متابعة كافة المراسلات وإدارة المهام.
|
||||||
|
<?php else: ?>
|
||||||
|
أنت مسجل كـ <strong>موظف</strong>. تابع مهامك المسندة إليك هنا.
|
||||||
|
<?php endif; ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="d-none d-md-block">
|
||||||
|
<?php if ($current_user['profile_image']): ?>
|
||||||
|
<img src="<?= $current_user['profile_image'] ?>?v=<?= time() ?>" alt="Profile" class="rounded-circle border border-3 border-white shadow" style="width: 100px; height: 100px; object-fit: cover;">
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="bg-white bg-opacity-25 rounded-circle d-flex align-items-center justify-content-center border border-3 border-white shadow" style="width: 100px; height: 100px;">
|
||||||
|
<i class="fas fa-user fa-3x text-white"></i>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4 mb-4">
|
||||||
|
<!-- Stats for everyone -->
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-primary border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-primary bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-tasks text-primary fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">مهامي</h6>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $my_total_assignments ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-warning border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-warning bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-clock text-warning fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">قيد التنفيذ</h6>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $my_pending_tasks ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($is_clerk): ?>
|
||||||
|
<!-- Clerk specific stats -->
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-info border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-info bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-download text-info fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">إجمالي الوارد</h6>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $total_inbound ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-success border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-success bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-upload text-success fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">إجمالي الصادر</h6>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $total_outbound ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<!-- Staff specific stats -->
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-info border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-info bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-envelope-open text-info fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">وارد من قبلي</h6>
|
||||||
|
<?php
|
||||||
|
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE created_by = ? AND type = 'inbound'");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$my_in_count = $stmt->fetchColumn();
|
||||||
|
?>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $my_in_count ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card h-100 p-3 shadow-sm border-0 border-start border-success border-4">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="bg-success bg-opacity-10 p-3 rounded-3 me-3">
|
||||||
|
<i class="fas fa-paper-plane text-success fs-4"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-muted mb-1">صادر من قبلي</h6>
|
||||||
|
<?php
|
||||||
|
$stmt = db()->prepare("SELECT COUNT(*) FROM mailbox WHERE created_by = ? AND type = 'outbound'");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$my_out_count = $stmt->fetchColumn();
|
||||||
|
?>
|
||||||
|
<h3 class="fw-bold mb-0"><?= $my_out_count ?></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Assignments Table -->
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card shadow-sm border-0 mb-4 h-100">
|
||||||
|
<div class="card-header bg-white py-3 border-bottom d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 fw-bold"><i class="fas fa-clipboard-list me-2 text-primary"></i> مهامي المسندة</h5>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="inbound.php?action=add" class="btn btn-sm btn-outline-primary">إضافة وارد</a>
|
||||||
|
<a href="outbound.php" class="btn btn-sm btn-outline-success">إضافة صادر</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<thead class="bg-light">
|
||||||
|
<tr>
|
||||||
|
<th class="ps-4">رقم القيد</th>
|
||||||
|
<th>الموضوع</th>
|
||||||
|
<th>الموعد النهائي</th>
|
||||||
|
<th>الحالة</th>
|
||||||
|
<th class="pe-4 text-center">الإجراء</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($my_assignments): ?>
|
||||||
|
<?php foreach ($my_assignments as $mail): ?>
|
||||||
|
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $mail['id'] ?>'">
|
||||||
|
<td class="ps-4 fw-bold text-primary"><?= $mail['ref_no'] ?></td>
|
||||||
|
<td><?= htmlspecialchars($mail['subject']) ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($mail['due_date']): ?>
|
||||||
|
<small class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger fw-bold' : 'text-muted' ?>">
|
||||||
|
<?= $mail['due_date'] ?>
|
||||||
|
</small>
|
||||||
|
<?php else: ?>
|
||||||
|
<small class="text-muted">-</small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?= getStatusBadge($mail) ?></td>
|
||||||
|
<td class="pe-4 text-center">
|
||||||
|
<a href="view_mail.php?id=<?= $mail['id'] ?>" class="btn btn-sm btn-light rounded-pill px-3">عرض</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center py-5 text-muted">
|
||||||
|
<i class="fas fa-check-double fa-3x mb-3 d-block text-success opacity-25"></i>
|
||||||
|
أنت على اطلاع بكافة مهامك! لا توجد مهام معلقة.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent Activity Sidebar -->
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<div class="card shadow-sm border-0 mb-4 h-100">
|
||||||
|
<div class="card-header bg-white py-3 border-bottom">
|
||||||
|
<h5 class="mb-0 fw-bold"><i class="fas fa-bell me-2 text-warning"></i> <?= $is_clerk ? 'آخر المراسلات' : 'نشاطاتي الأخيرة' ?></h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0" style="max-height: 500px; overflow-y: auto;">
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
<?php if ($recent_activity): ?>
|
||||||
|
<?php foreach ($recent_activity as $act): ?>
|
||||||
|
<a href="view_mail.php?id=<?= $act['id'] ?>" class="list-group-item list-group-item-action p-3 border-0 border-bottom">
|
||||||
|
<div class="d-flex w-100 justify-content-between mb-1">
|
||||||
|
<h6 class="mb-1 fw-bold text-truncate" title="<?= htmlspecialchars($act['subject']) ?>"><?= htmlspecialchars($act['subject']) ?></h6>
|
||||||
|
<small class="text-muted"><?= date('m-d', strtotime($act['updated_at'])) ?></small>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="fas <?= $act['type'] == 'inbound' ? 'fa-arrow-down text-primary' : 'fa-arrow-up text-success' ?> me-1"></i>
|
||||||
|
<?= $act['ref_no'] ?>
|
||||||
|
</small>
|
||||||
|
<?= getStatusBadge($act) ?>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="text-center py-5 text-muted">
|
||||||
|
لا يوجد نشاط مسجل
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-light text-center py-2">
|
||||||
|
<a href="inbound.php" class="small text-decoration-none">عرض كافة المراسلات <i class="fas fa-chevron-left ms-1"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
@ -4,10 +4,12 @@ require_once __DIR__ . '/includes/header.php';
|
|||||||
$id = $_GET['id'] ?? 0;
|
$id = $_GET['id'] ?? 0;
|
||||||
if (!$id) redirect('index.php');
|
if (!$id) redirect('index.php');
|
||||||
|
|
||||||
$stmt = db()->prepare("SELECT m.*, u1.full_name as assigned_name, u2.full_name as creator_name
|
$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 mailbox m
|
||||||
LEFT JOIN users u1 ON m.assigned_to = u1.id
|
LEFT JOIN users u1 ON m.assigned_to = u1.id
|
||||||
LEFT JOIN users u2 ON m.created_by = u2.id
|
LEFT JOIN users u2 ON m.created_by = u2.id
|
||||||
|
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
||||||
WHERE m.id = ?");
|
WHERE m.id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$mail = $stmt->fetch();
|
$mail = $stmt->fetch();
|
||||||
@ -116,24 +118,41 @@ function isPreviewable($fileName) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label class="text-muted small">رقم القيد</label>
|
<label class="text-muted small">رقم القيد</label>
|
||||||
<p class="fw-bold fs-5 text-primary"><?= $mail['ref_no'] ?></p>
|
<p class="fw-bold fs-5 text-primary"><?= $mail['ref_no'] ?></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label class="text-muted small">تاريخ التسجيل</label>
|
<label class="text-muted small">تاريخ التسجيل</label>
|
||||||
<p class="fw-bold"><?= $mail['date_registered'] ?></p>
|
<p class="fw-bold"><?= $mail['date_registered'] ?></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
|
<label class="text-muted small">الموعد النهائي</label>
|
||||||
|
<p class="fw-bold">
|
||||||
|
<?php if ($mail['due_date']): ?>
|
||||||
|
<span class="<?= (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed') ? 'text-danger' : '' ?>">
|
||||||
|
<?= $mail['due_date'] ?>
|
||||||
|
<?php if (strtotime($mail['due_date']) < time() && $mail['status_name'] != 'closed'): ?>
|
||||||
|
<i class="fas fa-exclamation-triangle ms-1"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">غير محدد</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
<label class="text-muted small">الحالة</label>
|
<label class="text-muted small">الحالة</label>
|
||||||
<p>
|
<p>
|
||||||
<?php if ($mail['status'] === 'received'): ?>
|
<?php
|
||||||
<span class="badge bg-secondary">تم الاستلام</span>
|
$s_name = $mail['status_name'] ?? 'غير معروف';
|
||||||
<?php elseif ($mail['status'] === 'in_progress'): ?>
|
$s_color = $mail['status_color'] ?? '#6c757d';
|
||||||
<span class="badge bg-info text-dark">قيد المعالجة</span>
|
$d_name = $s_name;
|
||||||
<?php elseif ($mail['status'] === 'closed'): ?>
|
if ($s_name == 'received') $d_name = 'تم الاستلام';
|
||||||
<span class="badge bg-success">مكتمل</span>
|
if ($s_name == 'in_progress') $d_name = 'قيد المعالجة';
|
||||||
<?php endif; ?>
|
if ($s_name == 'closed') $d_name = 'مكتمل';
|
||||||
|
?>
|
||||||
|
<span class="badge" style="background-color: <?= $s_color ?>;"><?= htmlspecialchars($d_name) ?></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@ -281,7 +300,7 @@ function isPreviewable($fileName) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a id="downloadBtn" href="#" class="btn btn-primary" download>تحميل الملف</a>
|
<a id="downloadBtn" href="#" class="btn btn-primary" download>تحميل الملف</a>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إغلاق</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إإغلاق</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user