add profile
This commit is contained in:
parent
5d112ecb1b
commit
fc07d00bbb
15
db/migrations/002_add_profiles.sql
Normal file
15
db/migrations/002_add_profiles.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-- Migration: Add User and Charity Profiles
|
||||||
|
ALTER TABLE users ADD COLUMN profile_image VARCHAR(255) DEFAULT NULL AFTER full_name;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS charity_settings (
|
||||||
|
id INT PRIMARY KEY DEFAULT 1,
|
||||||
|
charity_name VARCHAR(255) NOT NULL DEFAULT 'جمعية خيرية',
|
||||||
|
charity_logo VARCHAR(255) DEFAULT NULL,
|
||||||
|
charity_favicon VARCHAR(255) DEFAULT NULL,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT single_row CHECK (id = 1)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Initial Charity Settings
|
||||||
|
INSERT INTO charity_settings (id, charity_name) VALUES (1, 'بريد الجمعية الخيرية')
|
||||||
|
ON DUPLICATE KEY UPDATE charity_name=charity_name;
|
||||||
88
inbound.php
88
inbound.php
@ -74,7 +74,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
|
|
||||||
<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>
|
||||||
<button type="button" class="btn btn-primary" onclick="openMailModal('add')">
|
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -136,7 +136,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<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", <?= json_encode($mail) ?>)' title="تعديل">
|
onclick="openMailModal('edit', <?= htmlspecialchars(json_encode($mail), ENT_QUOTES, 'UTF-8') ?>)" 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>
|
||||||
@ -156,43 +156,43 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<!-- Mail Modal -->
|
<!-- Mail Modal -->
|
||||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content border-0 shadow">
|
||||||
<div class="modal-header">
|
<div class="modal-header bg-primary text-white">
|
||||||
<h5 class="modal-title" id="mailModalLabel">إضافة بريد وارد جديد</h5>
|
<h5 class="modal-title fw-bold" id="mailModalLabel">إضافة بريد وارد جديد</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form id="mailForm" method="POST">
|
<form id="mailForm" method="POST">
|
||||||
<div class="modal-body">
|
<div class="modal-body p-4">
|
||||||
<input type="hidden" name="action" id="modalAction" value="add">
|
<input type="hidden" name="action" id="modalAction" value="add">
|
||||||
<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-6">
|
||||||
<label class="form-label">رقم القيد <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-6">
|
||||||
<label class="form-label">تاريخ التسجيل</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-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">المرسل</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">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">المستلم الداخلي (القسم/الموظف)</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">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">الموضوع <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">الموضوع <span class="text-danger">*</span></label>
|
||||||
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">الوصف / ملاحظات</label>
|
<label class="form-label fw-bold">الوصف / ملاحظات</label>
|
||||||
<textarea name="description" id="modalDescription" class="form-control" rows="3"></textarea>
|
<textarea name="description" id="modalDescription" class="form-control" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">الحالة</label>
|
<label class="form-label fw-bold">الحالة</label>
|
||||||
<select name="status" id="modalStatus" class="form-select">
|
<select name="status" id="modalStatus" class="form-select">
|
||||||
<option value="received">تم الاستلام</option>
|
<option value="received">تم الاستلام</option>
|
||||||
<option value="in_progress">قيد المعالجة</option>
|
<option value="in_progress">قيد المعالجة</option>
|
||||||
@ -200,7 +200,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">الموظف المسؤول</label>
|
<label class="form-label fw-bold">الموظف المسؤول</label>
|
||||||
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
||||||
<option value="">-- اختر موظف --</option>
|
<option value="">-- اختر موظف --</option>
|
||||||
<?php foreach ($users_list as $u): ?>
|
<?php foreach ($users_list as $u): ?>
|
||||||
@ -210,9 +210,9 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer bg-light">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||||
<button type="submit" class="btn btn-primary">حفظ البيانات</button>
|
<button type="submit" class="btn btn-primary px-4">حفظ البيانات</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -220,9 +220,19 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const mailModal = new bootstrap.Modal(document.getElementById('mailModal'));
|
let mailModal;
|
||||||
|
|
||||||
function openMailModal(action, data = null) {
|
function openMailModal(action, data = null) {
|
||||||
|
if (!mailModal) {
|
||||||
|
const modalEl = document.getElementById('mailModal');
|
||||||
|
if (typeof bootstrap !== 'undefined') {
|
||||||
|
mailModal = new bootstrap.Modal(modalEl);
|
||||||
|
} else {
|
||||||
|
console.error('Bootstrap not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const label = document.getElementById('mailModalLabel');
|
const label = document.getElementById('mailModalLabel');
|
||||||
const modalAction = document.getElementById('modalAction');
|
const modalAction = document.getElementById('modalAction');
|
||||||
const modalId = document.getElementById('modalId');
|
const modalId = document.getElementById('modalId');
|
||||||
@ -252,7 +262,7 @@ function openMailModal(action, data = null) {
|
|||||||
label.textContent = 'تعديل البريد الوارد';
|
label.textContent = 'تعديل البريد الوارد';
|
||||||
modalId.value = data.id;
|
modalId.value = data.id;
|
||||||
Object.keys(fields).forEach(key => {
|
Object.keys(fields).forEach(key => {
|
||||||
fields[key].value = data[key] || '';
|
if (fields[key]) fields[key].value = data[key] || '';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,24 +273,30 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<?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'])): ?>
|
||||||
const data = {
|
const errorData = <?= json_encode([
|
||||||
id: '<?= $_POST['id'] ?? 0 ?>',
|
'id' => $_POST['id'] ?? 0,
|
||||||
ref_no: '<?= addslashes($_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'),
|
||||||
sender: '<?= addslashes($_POST['sender'] ?? '') ?>',
|
'sender' => $_POST['sender'] ?? '',
|
||||||
recipient: '<?= addslashes($_POST['recipient'] ?? '') ?>',
|
'recipient' => $_POST['recipient'] ?? '',
|
||||||
subject: '<?= addslashes($_POST['subject'] ?? '') ?>',
|
'subject' => $_POST['subject'] ?? '',
|
||||||
description: '<?= addslashes($_POST['description'] ?? '') ?>',
|
'description' => $_POST['description'] ?? '',
|
||||||
status: '<?= $_POST['status'] ?? 'received' ?>',
|
'status' => $_POST['status'] ?? 'received',
|
||||||
assigned_to: '<?= $_POST['assigned_to'] ?? '' ?>'
|
'assigned_to' => $_POST['assigned_to'] ?? ''
|
||||||
};
|
]) ?>;
|
||||||
openMailModal('<?= $_POST['action'] ?>', data);
|
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||||
openMailModal('add');
|
openMailModal('add');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
});
|
});
|
||||||
|
|
||||||
function confirmDelete(id) {
|
function confirmDelete(id) {
|
||||||
|
if (typeof Swal === 'undefined') {
|
||||||
|
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||||
|
window.location.href = 'inbound.php?action=delete&id=' + id;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'هل أنت متأكد؟',
|
title: 'هل أنت متأكد؟',
|
||||||
text: "لا يمكن التراجع عن عملية الحذف!",
|
text: "لا يمكن التراجع عن عملية الحذف!",
|
||||||
@ -298,4 +314,14 @@ function confirmDelete(id) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.modal-header.bg-primary {
|
||||||
|
background-color: #0d6efd !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
@ -1,13 +1,9 @@
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bootstrap 5 JS Bundle -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<!-- SweetAlert2 -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// Global JS functions if needed
|
// Global JS functions if needed
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -18,19 +18,43 @@ function redirect($path) {
|
|||||||
if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
||||||
redirect('login.php');
|
redirect('login.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch charity settings
|
||||||
|
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
||||||
|
$charity = $stmt->fetch();
|
||||||
|
$charity_name = $charity['charity_name'] ?? 'بريد الجمعية';
|
||||||
|
$charity_logo = $charity['charity_logo'] ?? null;
|
||||||
|
$charity_favicon = $charity['charity_favicon'] ?? null;
|
||||||
|
|
||||||
|
// Fetch current user info if logged in
|
||||||
|
$current_user = null;
|
||||||
|
if (isLoggedIn()) {
|
||||||
|
$stmt = db()->prepare("SELECT full_name, profile_image FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$_SESSION['user_id']]);
|
||||||
|
$current_user = $stmt->fetch();
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ar" dir="rtl">
|
<html lang="ar" dir="rtl">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>بريد الجمعية الخيرية</title>
|
<title><?= htmlspecialchars($charity_name) ?></title>
|
||||||
|
<?php if ($charity_favicon): ?>
|
||||||
|
<link rel="icon" type="image/x-icon" href="<?= $charity_favicon ?>?v=<?= time() ?>">
|
||||||
|
<?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">
|
||||||
<!-- 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">
|
||||||
|
|
||||||
|
<!-- 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/sweetalert2@11"></script>
|
||||||
|
<script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: 'Cairo', sans-serif;
|
font-family: 'Cairo', sans-serif;
|
||||||
@ -40,7 +64,7 @@ if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
padding-top: 2rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
.nav-link {
|
.nav-link {
|
||||||
color: #333;
|
color: #333;
|
||||||
@ -64,6 +88,23 @@ if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
|||||||
.status-received { background-color: #e9ecef; color: #495057; }
|
.status-received { background-color: #e9ecef; color: #495057; }
|
||||||
.status-in_progress { background-color: #cff4fc; color: #055160; }
|
.status-in_progress { background-color: #cff4fc; color: #055160; }
|
||||||
.status-closed { background-color: #d1e7dd; color: #0f5132; }
|
.status-closed { background-color: #d1e7dd; color: #0f5132; }
|
||||||
|
|
||||||
|
/* Modal Header Styling */
|
||||||
|
.modal-header.bg-primary {
|
||||||
|
background-color: #0d6efd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile-img {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 2px solid #0d6efd;
|
||||||
|
}
|
||||||
|
.charity-logo {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -75,8 +116,24 @@ if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
|||||||
<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 collapse">
|
||||||
<div class="position-sticky">
|
<div class="position-sticky">
|
||||||
<div class="text-center mb-4">
|
<div class="text-center mb-4">
|
||||||
<h5 class="fw-bold">بريد الجمعية</h5>
|
<?php if ($charity_logo): ?>
|
||||||
|
<img src="<?= $charity_logo ?>?v=<?= time() ?>" alt="Logo" class="charity-logo mb-2">
|
||||||
|
<?php endif; ?>
|
||||||
|
<h5 class="fw-bold mt-2"><?= htmlspecialchars($charity_name) ?></h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="user-info text-center mb-4 py-3 border-bottom border-top">
|
||||||
|
<?php if ($current_user['profile_image']): ?>
|
||||||
|
<img src="<?= $current_user['profile_image'] ?>?v=<?= time() ?>" alt="Profile" class="user-profile-img mb-2">
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="user-profile-img bg-light mx-auto d-flex align-items-center justify-content-center mb-2">
|
||||||
|
<i class="fas fa-user text-secondary fa-2x"></i>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="small fw-bold"><?= htmlspecialchars($current_user['full_name'] ?? $_SESSION['username']) ?></div>
|
||||||
|
<div class="small text-muted"><?= $_SESSION['user_role'] === 'admin' ? 'مدير النظام' : 'موظف' ?></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' ? 'active' : '' ?>" href="index.php">
|
||||||
@ -100,7 +157,12 @@ if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php') {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<li class="nav-item mt-5">
|
<li class="nav-item">
|
||||||
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'profile.php' ? 'active' : '' ?>" href="profile.php">
|
||||||
|
<i class="fas fa-user-circle me-2"></i> الملف الشخصي
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item mt-4">
|
||||||
<a class="nav-link text-danger" href="logout.php">
|
<a class="nav-link text-danger" href="logout.php">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i> تسجيل الخروج
|
<i class="fas fa-sign-out-alt me-2"></i> تسجيل الخروج
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
170
outbound.php
170
outbound.php
@ -1,6 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
|
||||||
|
// Safe truncation helper
|
||||||
|
if (!function_exists('truncate_text')) {
|
||||||
|
function truncate_text($text, $limit = 100) {
|
||||||
|
$text = strip_tags($text);
|
||||||
|
if (function_exists('mb_strimwidth')) {
|
||||||
|
return mb_strimwidth($text, 0, $limit, "...");
|
||||||
|
}
|
||||||
|
if (strlen($text) <= $limit) return $text;
|
||||||
|
return substr($text, 0, $limit) . "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$error = '';
|
$error = '';
|
||||||
$success = '';
|
$success = '';
|
||||||
|
|
||||||
@ -43,8 +55,9 @@ 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)) {
|
||||||
$stmt = db()->prepare("INSERT INTO attachments (mail_id, file_path, file_name, file_size) VALUES (?, ?, ?, ?)");
|
// Default display_name to original name for multiple uploads
|
||||||
$stmt->execute([$mail_id, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
$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]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +110,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
|
|
||||||
<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>
|
||||||
<button type="button" class="btn btn-primary" onclick="openMailModal('add')">
|
<button type="button" class="btn btn-primary shadow-sm" onclick="openMailModal('add')">
|
||||||
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
<i class="fas fa-plus-circle me-1"></i> إضافة جديد
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -145,7 +158,7 @@ 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><?= mb_strimwidth(strip_tags($mail['subject']), 0, 100, "...") ?></td>
|
<td><?= truncate_text($mail['subject'], 100) ?></td>
|
||||||
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
<td><?= htmlspecialchars($mail['recipient']) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if ($mail['status'] === 'received'): ?>
|
<?php if ($mail['status'] === 'received'): ?>
|
||||||
@ -159,7 +172,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<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", <?= json_encode($mail) ?>)' title="تعديل">
|
onclick="openMailModal('edit', <?= htmlspecialchars(json_encode($mail), ENT_QUOTES, 'UTF-8') ?>)" 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>
|
||||||
@ -179,48 +192,48 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<!-- Mail Modal -->
|
<!-- Mail Modal -->
|
||||||
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
<div class="modal fade" id="mailModal" tabindex="-1" aria-labelledby="mailModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl">
|
<div class="modal-dialog modal-xl">
|
||||||
<div class="modal-content">
|
<div class="modal-content border-0 shadow">
|
||||||
<div class="modal-header">
|
<div class="modal-header bg-success text-white">
|
||||||
<h5 class="modal-title" id="mailModalLabel">إضافة بريد صادر جديد</h5>
|
<h5 class="modal-title fw-bold" id="mailModalLabel">إضافة بريد صادر جديد</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form id="mailForm" method="POST" enctype="multipart/form-data">
|
<form id="mailForm" method="POST" enctype="multipart/form-data">
|
||||||
<div class="modal-body">
|
<div class="modal-body p-4">
|
||||||
<input type="hidden" name="action" id="modalAction" value="add">
|
<input type="hidden" name="action" id="modalAction" value="add">
|
||||||
<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-6">
|
||||||
<label class="form-label">رقم القيد <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-6">
|
||||||
<label class="form-label">تاريخ التسجيل</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-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">المستلم الخارجي (الجهة المستلمة)</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">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">المرسل الداخلي (القسم/الموظف)</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">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">الموضوع <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">الموضوع <span class="text-danger">*</span></label>
|
||||||
<textarea name="subject" id="subject_editor" class="form-control" rows="2"></textarea>
|
<input type="text" name="subject" id="modalSubject" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">الوصف / ملاحظات</label>
|
<label class="form-label fw-bold">الوصف / ملاحظات</label>
|
||||||
<textarea name="description" id="description_editor" class="form-control" rows="5"></textarea>
|
<textarea name="description" id="description_editor" class="form-control" rows="5"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label">المرفقات</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 class="form-text text-muted">يمكنك اختيار ملفات متعددة.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">الحالة</label>
|
<label class="form-label fw-bold">الحالة</label>
|
||||||
<select name="status" id="modalStatus" class="form-select">
|
<select name="status" id="modalStatus" class="form-select">
|
||||||
<option value="received">تم الاستلام</option>
|
<option value="received">تم الاستلام</option>
|
||||||
<option value="in_progress">قيد المعالجة</option>
|
<option value="in_progress">قيد المعالجة</option>
|
||||||
@ -228,7 +241,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label class="form-label">الموظف المسؤول</label>
|
<label class="form-label fw-bold">الموظف المسؤول</label>
|
||||||
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
<select name="assigned_to" id="modalAssignedTo" class="form-select">
|
||||||
<option value="">-- اختر موظف --</option>
|
<option value="">-- اختر موظف --</option>
|
||||||
<?php foreach ($users_list as $u): ?>
|
<?php foreach ($users_list as $u): ?>
|
||||||
@ -238,37 +251,47 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer bg-light">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||||
<button type="submit" class="btn btn-primary">حفظ البيانات</button>
|
<button type="submit" class="btn btn-primary px-4">حفظ البيانات</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
let subjectEditor, descriptionEditor;
|
let descriptionEditor;
|
||||||
|
let mailModal;
|
||||||
|
|
||||||
function initEditors() {
|
function initEditors() {
|
||||||
return Promise.all([
|
if (typeof ClassicEditor === 'undefined') {
|
||||||
ClassicEditor.create(document.querySelector('#subject_editor'), {
|
console.error('CKEditor not loaded');
|
||||||
language: { content: 'ar', ui: 'ar' },
|
return Promise.resolve();
|
||||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'undo', 'redo']
|
}
|
||||||
}).then(editor => { subjectEditor = editor; }),
|
|
||||||
|
const config = {
|
||||||
|
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'undo', 'redo']
|
||||||
|
};
|
||||||
|
|
||||||
ClassicEditor.create(document.querySelector('#description_editor'), {
|
return ClassicEditor.create(document.querySelector('#description_editor'), config)
|
||||||
language: { content: 'ar', ui: 'ar' },
|
.then(editor => { descriptionEditor = editor; })
|
||||||
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', '|', 'undo', 'redo']
|
.catch(err => {
|
||||||
}).then(editor => { descriptionEditor = editor; })
|
console.error('CKEditor Init Error:', err);
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const mailModalElement = document.getElementById('mailModal');
|
|
||||||
const mailModal = new bootstrap.Modal(mailModalElement);
|
|
||||||
|
|
||||||
function openMailModal(action, data = null) {
|
function openMailModal(action, data = null) {
|
||||||
|
if (!mailModal) {
|
||||||
|
const modalEl = document.getElementById('mailModal');
|
||||||
|
if (typeof bootstrap !== 'undefined') {
|
||||||
|
mailModal = new bootstrap.Modal(modalEl);
|
||||||
|
} else {
|
||||||
|
console.error('Bootstrap not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const label = document.getElementById('mailModalLabel');
|
const label = document.getElementById('mailModalLabel');
|
||||||
const modalAction = document.getElementById('modalAction');
|
const modalAction = document.getElementById('modalAction');
|
||||||
const modalId = document.getElementById('modalId');
|
const modalId = document.getElementById('modalId');
|
||||||
@ -278,6 +301,7 @@ function openMailModal(action, data = null) {
|
|||||||
date_registered: document.getElementById('modalDateRegistered'),
|
date_registered: document.getElementById('modalDateRegistered'),
|
||||||
sender: document.getElementById('modalSender'),
|
sender: document.getElementById('modalSender'),
|
||||||
recipient: document.getElementById('modalRecipient'),
|
recipient: document.getElementById('modalRecipient'),
|
||||||
|
subject: document.getElementById('modalSubject'),
|
||||||
status: document.getElementById('modalStatus'),
|
status: document.getElementById('modalStatus'),
|
||||||
assigned_to: document.getElementById('modalAssignedTo')
|
assigned_to: document.getElementById('modalAssignedTo')
|
||||||
};
|
};
|
||||||
@ -288,50 +312,65 @@ function openMailModal(action, data = null) {
|
|||||||
label.textContent = 'إضافة بريد صادر جديد';
|
label.textContent = 'إضافة بريد صادر جديد';
|
||||||
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 (fields[key]) {
|
||||||
else if (key === 'status') fields[key].value = 'received';
|
if (key === 'date_registered') fields[key].value = '<?= date('Y-m-d') ?>';
|
||||||
else fields[key].value = '';
|
else if (key === 'status') fields[key].value = 'received';
|
||||||
|
else fields[key].value = '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (subjectEditor) subjectEditor.setData('');
|
|
||||||
if (descriptionEditor) descriptionEditor.setData('');
|
if (descriptionEditor) descriptionEditor.setData('');
|
||||||
|
else document.getElementById('description_editor').value = '';
|
||||||
} else {
|
} else {
|
||||||
label.textContent = 'تعديل البريد الصادر';
|
label.textContent = 'تعديل البريد الصادر';
|
||||||
modalId.value = data.id;
|
modalId.value = data.id;
|
||||||
Object.keys(fields).forEach(key => {
|
Object.keys(fields).forEach(key => {
|
||||||
fields[key].value = data[key] || '';
|
if (fields[key]) fields[key].value = data[key] || '';
|
||||||
});
|
});
|
||||||
if (subjectEditor) subjectEditor.setData(data.subject || '');
|
|
||||||
if (descriptionEditor) descriptionEditor.setData(data.description || '');
|
if (descriptionEditor) descriptionEditor.setData(data.description || '');
|
||||||
|
else document.getElementById('description_editor').value = data.description || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
mailModal.show();
|
mailModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
initEditors().then(() => {
|
initEditors().finally(() => {
|
||||||
// Deep link or error handling
|
// 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'])): ?>
|
||||||
const data = {
|
const errorData = <?= json_encode([
|
||||||
id: '<?= $_POST['id'] ?? 0 ?>',
|
'id' => $_POST['id'] ?? 0,
|
||||||
ref_no: '<?= addslashes($_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'),
|
||||||
sender: '<?= addslashes($_POST['sender'] ?? '') ?>',
|
'sender' => $_POST['sender'] ?? '',
|
||||||
recipient: '<?= addslashes($_POST['recipient'] ?? '') ?>',
|
'recipient' => $_POST['recipient'] ?? '',
|
||||||
subject: `<?= addslashes($_POST['subject'] ?? '') ?>`,
|
'subject' => $_POST['subject'] ?? '',
|
||||||
description: `<?= addslashes($_POST['description'] ?? '') ?>`,
|
'description' => $_POST['description'] ?? '',
|
||||||
status: '<?= $_POST['status'] ?? 'received' ?>',
|
'status' => $_POST['status'] ?? 'received',
|
||||||
assigned_to: '<?= $_POST['assigned_to'] ?? '' ?>'
|
'assigned_to' => $_POST['assigned_to'] ?? ''
|
||||||
};
|
]) ?>;
|
||||||
openMailModal('<?= $_POST['action'] ?>', data);
|
openMailModal('<?= $_POST['action'] ?>', errorData);
|
||||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||||
openMailModal('add');
|
openMailModal('add');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle form submission to ensure CKEditor data is synced
|
||||||
|
document.getElementById('mailForm').addEventListener('submit', function() {
|
||||||
|
if (descriptionEditor) descriptionEditor.updateSourceElement();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function confirmDelete(id) {
|
function confirmDelete(id) {
|
||||||
|
if (typeof Swal === 'undefined') {
|
||||||
|
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||||
|
window.location.href = 'outbound.php?action=delete&id=' + id;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'هل أنت متأكد؟',
|
title: 'هل أنت متأكد؟',
|
||||||
text: "لا يمكن التراجع عن عملية الحذف!",
|
text: "لا يمكن التراجع عن عملية الحذف!",
|
||||||
@ -351,11 +390,22 @@ function confirmDelete(id) {
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.ck-editor__editable_inline {
|
.ck-editor__editable_inline {
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
#description_editor + .ck-editor .ck-editor__editable_inline {
|
|
||||||
min-height: 250px;
|
min-height: 250px;
|
||||||
}
|
}
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
/* Specific styling for green header */
|
||||||
|
.modal-header.bg-success {
|
||||||
|
background-color: #198754 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
|
|||||||
165
profile.php
Normal file
165
profile.php
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$success_msg = '';
|
||||||
|
$error_msg = '';
|
||||||
|
|
||||||
|
// Fetch current user data
|
||||||
|
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
// Fetch charity settings
|
||||||
|
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
||||||
|
$charity = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (isset($_POST['update_profile'])) {
|
||||||
|
$full_name = $_POST['full_name'];
|
||||||
|
$password = $_POST['password'];
|
||||||
|
$profile_image = $user['profile_image'];
|
||||||
|
|
||||||
|
// Handle Profile Image Upload
|
||||||
|
if (isset($_FILES['profile_image']) && $_FILES['profile_image']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$upload_dir = 'uploads/profiles/';
|
||||||
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||||
|
|
||||||
|
$file_ext = pathinfo($_FILES['profile_image']['name'], PATHINFO_EXTENSION);
|
||||||
|
$new_file_name = time() . '_u' . $user_id . '.' . $file_ext;
|
||||||
|
$target_file = $upload_dir . $new_file_name;
|
||||||
|
|
||||||
|
if (move_uploaded_file($_FILES['profile_image']['tmp_name'], $target_file)) {
|
||||||
|
$profile_image = $target_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($password)) {
|
||||||
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
$stmt = db()->prepare("UPDATE users SET full_name = ?, password = ?, profile_image = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$full_name, $hashed_password, $profile_image, $user_id]);
|
||||||
|
} else {
|
||||||
|
$stmt = db()->prepare("UPDATE users SET full_name = ?, profile_image = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$full_name, $profile_image, $user_id]);
|
||||||
|
}
|
||||||
|
$success_msg = 'تم تحديث الملف الشخصي بنجاح';
|
||||||
|
// Refresh user data
|
||||||
|
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['update_charity']) && isAdmin()) {
|
||||||
|
$charity_name = $_POST['charity_name'];
|
||||||
|
$charity_logo = $charity['charity_logo'];
|
||||||
|
$charity_favicon = $charity['charity_favicon'];
|
||||||
|
|
||||||
|
$upload_dir = 'uploads/charity/';
|
||||||
|
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) {
|
||||||
|
$file_ext = pathinfo($_FILES['charity_logo']['name'], PATHINFO_EXTENSION);
|
||||||
|
$new_logo = 'logo_' . time() . '.' . $file_ext;
|
||||||
|
if (move_uploaded_file($_FILES['charity_logo']['tmp_name'], $upload_dir . $new_logo)) {
|
||||||
|
$charity_logo = $upload_dir . $new_logo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Favicon Upload
|
||||||
|
if (isset($_FILES['charity_favicon']) && $_FILES['charity_favicon']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$file_ext = pathinfo($_FILES['charity_favicon']['name'], PATHINFO_EXTENSION);
|
||||||
|
$new_favicon = 'favicon_' . time() . '.' . $file_ext;
|
||||||
|
if (move_uploaded_file($_FILES['charity_favicon']['tmp_name'], $upload_dir . $new_favicon)) {
|
||||||
|
$charity_favicon = $upload_dir . $new_favicon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = db()->prepare("UPDATE charity_settings SET charity_name = ?, charity_logo = ?, charity_favicon = ? WHERE id = 1");
|
||||||
|
$stmt->execute([$charity_name, $charity_logo, $charity_favicon]);
|
||||||
|
$success_msg = 'تم تحديث إعدادات الجمعية بنجاح';
|
||||||
|
|
||||||
|
// Refresh charity data
|
||||||
|
$stmt = db()->query("SELECT * FROM charity_settings WHERE id = 1");
|
||||||
|
$charity = $stmt->fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 mb-4">
|
||||||
|
<h2 class="fw-bold"><i class="fas fa-user-circle me-2"></i> الملف الشخصي والإعدادات</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($success_msg): ?>
|
||||||
|
<div class="alert alert-success"><?= $success_msg ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($error_msg): ?>
|
||||||
|
<div class="alert alert-danger"><?= $error_msg ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card p-4">
|
||||||
|
<h4 class="mb-4">تعديل الملف الشخصي</h4>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<?php if ($user['profile_image']): ?>
|
||||||
|
<img src="<?= $user['profile_image'] ?>" alt="Profile" class="rounded-circle" style="width: 150px; height: 150px; object-fit: cover; border: 3px solid #0d6efd;">
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="rounded-circle bg-light d-inline-flex align-items-center justify-content-center" style="width: 150px; height: 150px; border: 3px solid #ddd;">
|
||||||
|
<i class="fas fa-user fa-5x text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">الصورة الشخصية</label>
|
||||||
|
<input type="file" name="profile_image" class="form-control" accept="image/*">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">الاسم الكامل</label>
|
||||||
|
<input type="text" name="full_name" class="form-control" value="<?= htmlspecialchars($user['full_name']) ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">كلمة المرور الجديدة (اتركها فارغة إذا لم ترغب في التغيير)</label>
|
||||||
|
<input type="password" name="password" class="form-control">
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="update_profile" class="btn btn-primary w-100">حفظ التغييرات</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (isAdmin()): ?>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card p-4">
|
||||||
|
<h4 class="mb-4">إعدادات الجمعية</h4>
|
||||||
|
<form method="POST" enctype="multipart/form-data">
|
||||||
|
<div class="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="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: 50px;">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="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>
|
||||||
|
<button type="submit" name="update_charity" class="btn btn-dark w-100">تحديث إعدادات الجمعية</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
BIN
uploads/attachments/1772212176_Invoice_8.pdf
Normal file
BIN
uploads/attachments/1772212176_Invoice_8.pdf
Normal file
Binary file not shown.
BIN
uploads/attachments/1772212948_Invoice_8 (1).pdf
Normal file
BIN
uploads/attachments/1772212948_Invoice_8 (1).pdf
Normal file
Binary file not shown.
215
users.php
215
users.php
@ -2,15 +2,12 @@
|
|||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
|
||||||
if (!isAdmin()) {
|
if (!isAdmin()) {
|
||||||
echo '<div class="alert alert-danger mt-4">غير مصرح لك بالوصول لهذه الصفحة.</div>';
|
redirect('index.php');
|
||||||
require_once __DIR__ . '/includes/footer.php';
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$error = '';
|
$error = '';
|
||||||
$success = '';
|
$success = '';
|
||||||
|
|
||||||
// Handle actions
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$action = $_POST['action'] ?? '';
|
$action = $_POST['action'] ?? '';
|
||||||
$username = $_POST['username'] ?? '';
|
$username = $_POST['username'] ?? '';
|
||||||
@ -19,18 +16,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$password = $_POST['password'] ?? '';
|
$password = $_POST['password'] ?? '';
|
||||||
$id = $_POST['id'] ?? 0;
|
$id = $_POST['id'] ?? 0;
|
||||||
|
|
||||||
if ($username && $full_name) {
|
if ($action === 'add') {
|
||||||
try {
|
if ($username && $password && $full_name) {
|
||||||
if ($action === 'add') {
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
if (!$password) {
|
try {
|
||||||
$error = 'يرجى إدخال كلمة المرور للمستخدم الجديد';
|
$stmt = db()->prepare("INSERT INTO users (username, password, full_name, role) VALUES (?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$username, $hashed_password, $full_name, $role]);
|
||||||
|
$success = 'تم إضافة المستخدم بنجاح';
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->getCode() == 23000) {
|
||||||
|
$error = 'اسم المستخدم موجود مسبقاً';
|
||||||
} else {
|
} else {
|
||||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||||
$stmt = db()->prepare("INSERT INTO users (username, full_name, role, password) VALUES (?, ?, ?, ?)");
|
|
||||||
$stmt->execute([$username, $full_name, $role, $hashed_password]);
|
|
||||||
$success = 'تمت إضافة المستخدم بنجاح';
|
|
||||||
}
|
}
|
||||||
} elseif ($action === 'edit') {
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'يرجى ملء جميع الحقول المطلوبة';
|
||||||
|
}
|
||||||
|
} elseif ($action === 'edit') {
|
||||||
|
if ($username && $full_name && $id) {
|
||||||
|
try {
|
||||||
if ($password) {
|
if ($password) {
|
||||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
$stmt = db()->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, password = ? WHERE id = ?");
|
$stmt = db()->prepare("UPDATE users SET username = ?, full_name = ?, role = ?, password = ? WHERE id = ?");
|
||||||
@ -40,32 +45,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$stmt->execute([$username, $full_name, $role, $id]);
|
$stmt->execute([$username, $full_name, $role, $id]);
|
||||||
}
|
}
|
||||||
$success = 'تم تحديث بيانات المستخدم بنجاح';
|
$success = 'تم تحديث بيانات المستخدم بنجاح';
|
||||||
}
|
} catch (PDOException $e) {
|
||||||
} catch (PDOException $e) {
|
|
||||||
if ($e->getCode() == 23000) {
|
|
||||||
$error = 'اسم المستخدم موجود مسبقاً';
|
|
||||||
} else {
|
|
||||||
$error = 'حدث خطأ: ' . $e->getMessage();
|
$error = 'حدث خطأ: ' . $e->getMessage();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'يرجى ملء جميع الحقول المطلوبة';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$error = 'يرجى ملء الحقول المطلوبة';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete action
|
|
||||||
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) {
|
||||||
$id = $_GET['id'];
|
if ($_GET['id'] != $_SESSION['user_id']) {
|
||||||
if ($id == $_SESSION['user_id']) {
|
|
||||||
$error = 'لا يمكنك حذف حسابك الحالي';
|
|
||||||
} else {
|
|
||||||
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
|
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$_GET['id']]);
|
||||||
$success = 'تم حذف المستخدم بنجاح';
|
$success = 'تم حذف المستخدم بنجاح';
|
||||||
|
} else {
|
||||||
|
$error = 'لا يمكنك حذف حسابك الحالي';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$users = db()->query("SELECT * FROM users ORDER BY created_at DESC")->fetchAll();
|
$stmt = db()->query("SELECT * FROM users ORDER BY created_at DESC");
|
||||||
|
$users = $stmt->fetchAll();
|
||||||
|
|
||||||
// Handle Deep Link for Edit
|
// Handle Deep Link for Edit
|
||||||
$deepLinkData = null;
|
$deepLinkData = null;
|
||||||
@ -78,8 +78,8 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
|
|
||||||
<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>
|
||||||
<button type="button" class="btn btn-primary" onclick="openUserModal('add')">
|
<button type="button" class="btn btn-primary shadow-sm" onclick="openUserModal('add')">
|
||||||
<i class="fas fa-user-plus me-1"></i> إضافة مستخدم
|
<i class="fas fa-user-plus me-1"></i> إضافة مستخدم جديد
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -97,15 +97,15 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0 mb-4">
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover align-middle mb-0">
|
<table class="table table-hover align-middle mb-0">
|
||||||
<thead class="bg-light">
|
<thead class="bg-light">
|
||||||
<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 class="pe-4 text-center">الإجراءات</th>
|
<th class="pe-4 text-center">الإجراءات</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -113,24 +113,27 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($users as $user): ?>
|
<?php foreach ($users as $user): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ps-4 fw-bold"><?= htmlspecialchars($user['username']) ?></td>
|
<td class="ps-4 fw-bold"><?= htmlspecialchars($user['full_name']) ?></td>
|
||||||
<td><?= htmlspecialchars($user['full_name']) ?></td>
|
<td><?= htmlspecialchars($user['username']) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php
|
<?php if ($user['role'] === 'admin'): ?>
|
||||||
$badge = 'bg-secondary';
|
<span class="badge bg-danger">مدير</span>
|
||||||
if ($user['role'] === 'admin') $badge = 'bg-danger';
|
<?php elseif ($user['role'] === 'clerk'): ?>
|
||||||
if ($user['role'] === 'clerk') $badge = 'bg-primary';
|
<span class="badge bg-warning text-dark">كاتب</span>
|
||||||
?>
|
<?php else: ?>
|
||||||
<span class="badge <?= $badge ?>"><?= $user['role'] ?></span>
|
<span class="badge bg-secondary">موظف</span>
|
||||||
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
<td><?= date('Y-m-d', strtotime($user['created_at'])) ?></td>
|
<td><?= $user['created_at'] ?></td>
|
||||||
<td class="pe-4 text-center">
|
<td class="pe-4 text-center">
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||||
onclick='openUserModal("edit", <?= json_encode($user) ?>)'>
|
onclick="openUserModal('edit', <?= htmlspecialchars(json_encode($user), ENT_QUOTES, 'UTF-8') ?>)">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i> تعديل
|
||||||
</button>
|
</button>
|
||||||
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
||||||
<a href="javascript:void(0)" onclick="confirmDelete(<?= $user['id'] ?>)" class="btn btn-sm btn-outline-danger"><i class="fas fa-trash"></i></a>
|
<a href="javascript:void(0)" onclick="confirmDelete(<?= $user['id'] ?>)" class="btn btn-sm btn-outline-danger">
|
||||||
|
<i class="fas fa-trash"></i> حذف
|
||||||
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -144,41 +147,40 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
<!-- User Modal -->
|
<!-- User Modal -->
|
||||||
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
<div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content border-0 shadow">
|
||||||
<div class="modal-header">
|
<div class="modal-header bg-primary text-white">
|
||||||
<h5 class="modal-title" id="userModalLabel">إضافة مستخدم جديد</h5>
|
<h5 class="modal-title fw-bold" id="userModalLabel">إضافة مستخدم جديد</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form id="userForm" method="POST">
|
<form id="userForm" method="POST">
|
||||||
<div class="modal-body">
|
<div class="modal-body p-4">
|
||||||
<input type="hidden" name="action" id="modalAction" value="add">
|
<input type="hidden" name="action" id="modalAction" value="add">
|
||||||
<input type="hidden" name="id" id="modalUserId" value="0">
|
<input type="hidden" name="id" id="modalId" value="0">
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">اسم المستخدم <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">الاسم الكامل</label>
|
||||||
<input type="text" name="username" id="modalUsername" class="form-control" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">الاسم الكامل <span class="text-danger">*</span></label>
|
|
||||||
<input type="text" name="full_name" id="modalFullName" class="form-control" required>
|
<input type="text" name="full_name" id="modalFullName" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label">الصلاحية</label>
|
<label class="form-label fw-bold">اسم المستخدم</label>
|
||||||
<select name="role" id="modalRole" class="form-select">
|
<input type="text" name="username" id="modalUsername" class="form-control" required>
|
||||||
<option value="staff">موظف (Staff)</option>
|
|
||||||
<option value="clerk">مدخل بيانات (Clerk)</option>
|
|
||||||
<option value="admin">مدير (Admin)</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" id="passwordLabel">كلمة المرور <span class="text-danger">*</span></label>
|
<label class="form-label fw-bold">كلمة المرور <span id="pwdHint" class="text-muted small"></span></label>
|
||||||
<input type="password" name="password" id="modalPassword" class="form-control">
|
<input type="password" name="password" id="modalPassword" class="form-control">
|
||||||
<small class="text-muted" id="passwordHelp" style="display:none;">اتركه فارغاً للمحافظة على الحالية</small>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label fw-bold">الدور</label>
|
||||||
|
<select name="role" id="modalRole" class="form-select">
|
||||||
|
<option value="staff">موظف</option>
|
||||||
|
<option value="clerk">كاتب</option>
|
||||||
|
<option value="admin">مدير</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer bg-light">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إلغاء</button>
|
||||||
<button type="submit" class="btn btn-primary">حفظ البيانات</button>
|
<button type="submit" class="btn btn-primary px-4">حفظ البيانات</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -186,39 +188,48 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const userModal = new bootstrap.Modal(document.getElementById('userModal'));
|
let userModal;
|
||||||
|
|
||||||
function openUserModal(action, data = null) {
|
function openUserModal(action, data = null) {
|
||||||
|
if (!userModal) {
|
||||||
|
const modalEl = document.getElementById('userModal');
|
||||||
|
if (typeof bootstrap !== 'undefined') {
|
||||||
|
userModal = new bootstrap.Modal(modalEl);
|
||||||
|
} else {
|
||||||
|
console.error('Bootstrap not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const label = document.getElementById('userModalLabel');
|
const label = document.getElementById('userModalLabel');
|
||||||
const modalAction = document.getElementById('modalAction');
|
const modalAction = document.getElementById('modalAction');
|
||||||
const modalUserId = document.getElementById('modalUserId');
|
const modalId = document.getElementById('modalId');
|
||||||
const modalUsername = document.getElementById('modalUsername');
|
|
||||||
const modalFullName = document.getElementById('modalFullName');
|
|
||||||
const modalRole = document.getElementById('modalRole');
|
|
||||||
const modalPassword = document.getElementById('modalPassword');
|
const modalPassword = document.getElementById('modalPassword');
|
||||||
const passwordLabel = document.getElementById('passwordLabel');
|
const pwdHint = document.getElementById('pwdHint');
|
||||||
const passwordHelp = document.getElementById('passwordHelp');
|
|
||||||
|
const fields = {
|
||||||
|
full_name: document.getElementById('modalFullName'),
|
||||||
|
username: document.getElementById('modalUsername'),
|
||||||
|
role: document.getElementById('modalRole')
|
||||||
|
};
|
||||||
|
|
||||||
modalAction.value = action;
|
modalAction.value = action;
|
||||||
|
|
||||||
if (action === 'add') {
|
if (action === 'add') {
|
||||||
label.textContent = 'إضافة مستخدم جديد';
|
label.textContent = 'إضافة مستخدم جديد';
|
||||||
modalUserId.value = '0';
|
modalId.value = '0';
|
||||||
modalUsername.value = '';
|
Object.keys(fields).forEach(key => fields[key].value = '');
|
||||||
modalFullName.value = '';
|
|
||||||
modalRole.value = 'staff';
|
modalRole.value = 'staff';
|
||||||
modalPassword.required = true;
|
modalPassword.required = true;
|
||||||
passwordLabel.innerHTML = 'كلمة المرور <span class="text-danger">*</span>';
|
pwdHint.textContent = '';
|
||||||
passwordHelp.style.display = 'none';
|
|
||||||
} else {
|
} else {
|
||||||
label.textContent = 'تعديل بيانات المستخدم';
|
label.textContent = 'تعديل بيانات المستخدم';
|
||||||
modalUserId.value = data.id;
|
modalId.value = data.id;
|
||||||
modalUsername.value = data.username;
|
Object.keys(fields).forEach(key => {
|
||||||
modalFullName.value = data.full_name;
|
if (fields[key]) fields[key].value = data[key] || '';
|
||||||
modalRole.value = data.role;
|
});
|
||||||
modalPassword.required = false;
|
modalPassword.required = false;
|
||||||
passwordLabel.innerHTML = 'كلمة المرور';
|
pwdHint.textContent = '(اتركه فارغاً للحفاظ على كلمة المرور الحالية)';
|
||||||
passwordHelp.style.display = 'block';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userModal.show();
|
userModal.show();
|
||||||
@ -228,22 +239,28 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
<?php if ($deepLinkData): ?>
|
<?php if ($deepLinkData): ?>
|
||||||
openUserModal('edit', <?= json_encode($deepLinkData) ?>);
|
openUserModal('edit', <?= json_encode($deepLinkData) ?>);
|
||||||
<?php elseif ($error && isset($_POST['action'])): ?>
|
<?php elseif ($error && isset($_POST['action'])): ?>
|
||||||
const data = {
|
const errorData = <?= json_encode([
|
||||||
id: '<?= $_POST['id'] ?? 0 ?>',
|
'id' => $_POST['id'] ?? 0,
|
||||||
username: '<?= addslashes($_POST['username'] ?? '') ?>',
|
'username' => $_POST['username'] ?? '',
|
||||||
full_name: '<?= addslashes($_POST['full_name'] ?? '') ?>',
|
'full_name' => $_POST['full_name'] ?? '',
|
||||||
role: '<?= $_POST['role'] ?? 'staff' ?>'
|
'role' => $_POST['role'] ?? 'staff'
|
||||||
};
|
]) ?>;
|
||||||
openUserModal('<?= $_POST['action'] ?>', data);
|
openUserModal('<?= $_POST['action'] ?>', errorData);
|
||||||
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
<?php elseif (isset($_GET['action']) && $_GET['action'] === 'add'): ?>
|
||||||
openUserModal('add');
|
openUserModal('add');
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
});
|
});
|
||||||
|
|
||||||
function confirmDelete(id) {
|
function confirmDelete(id) {
|
||||||
|
if (typeof Swal === 'undefined') {
|
||||||
|
if (confirm('هل أنت متأكد من الحذف؟')) {
|
||||||
|
window.location.href = 'users.php?action=delete&id=' + id;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'هل أنت متأكد؟',
|
title: 'هل أنت متأكد؟',
|
||||||
text: "سيتم حذف المستخدم بشكل نهائي!",
|
text: "لا يمكن التراجع عن عملية الحذف!",
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonColor: '#d33',
|
confirmButtonColor: '#d33',
|
||||||
@ -258,4 +275,14 @@ function confirmDelete(id) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<style>
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.modal-header.bg-primary {
|
||||||
|
background-color: #0d6efd !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
149
view_mail.php
149
view_mail.php
@ -30,6 +30,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_comment'])) {
|
|||||||
// Handle Attachment upload
|
// Handle Attachment upload
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
||||||
$file = $_FILES['attachment'];
|
$file = $_FILES['attachment'];
|
||||||
|
$display_name = $_POST['display_name'] ?? '';
|
||||||
if ($file['error'] === 0) {
|
if ($file['error'] === 0) {
|
||||||
$upload_dir = 'uploads/attachments/';
|
$upload_dir = 'uploads/attachments/';
|
||||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||||
@ -38,8 +39,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
|||||||
$target_path = $upload_dir . $file_name;
|
$target_path = $upload_dir . $file_name;
|
||||||
|
|
||||||
if (move_uploaded_file($file['tmp_name'], $target_path)) {
|
if (move_uploaded_file($file['tmp_name'], $target_path)) {
|
||||||
$stmt = db()->prepare("INSERT INTO attachments (mail_id, 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([$id, $target_path, $file['name'], $file['size']]);
|
$stmt->execute([$id, $display_name, $target_path, $file['name'], $file['size']]);
|
||||||
$success = 'تم رفع الملف بنجاح';
|
$success = 'تم رفع الملف بنجاح';
|
||||||
} else {
|
} else {
|
||||||
$error = 'فشل في رفع الملف';
|
$error = 'فشل في رفع الملف';
|
||||||
@ -47,6 +48,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['attachment'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle Attachment deletion
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_attachment'])) {
|
||||||
|
$attachment_id = $_POST['attachment_id'] ?? 0;
|
||||||
|
if ($attachment_id) {
|
||||||
|
$stmt = db()->prepare("SELECT * FROM attachments WHERE id = ?");
|
||||||
|
$stmt->execute([$attachment_id]);
|
||||||
|
$attachment = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($attachment) {
|
||||||
|
// Delete file from disk
|
||||||
|
if (file_exists($attachment['file_path'])) {
|
||||||
|
unlink($attachment['file_path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete record from DB
|
||||||
|
$stmt = db()->prepare("DELETE FROM attachments WHERE id = ?");
|
||||||
|
$stmt->execute([$attachment_id]);
|
||||||
|
$success = 'تم حذف المرفق بنجاح';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$comments = db()->prepare("SELECT c.*, u.full_name FROM comments c LEFT JOIN users u ON c.user_id = u.id WHERE c.mail_id = ? ORDER BY c.created_at DESC");
|
$comments = db()->prepare("SELECT c.*, u.full_name FROM comments c LEFT JOIN users u ON c.user_id = u.id WHERE c.mail_id = ? ORDER BY c.created_at DESC");
|
||||||
$comments->execute([$id]);
|
$comments->execute([$id]);
|
||||||
$mail_comments = $comments->fetchAll();
|
$mail_comments = $comments->fetchAll();
|
||||||
@ -54,6 +77,12 @@ $mail_comments = $comments->fetchAll();
|
|||||||
$attachments = db()->prepare("SELECT * FROM attachments WHERE mail_id = ? ORDER BY created_at DESC");
|
$attachments = db()->prepare("SELECT * FROM attachments WHERE mail_id = ? ORDER BY created_at DESC");
|
||||||
$attachments->execute([$id]);
|
$attachments->execute([$id]);
|
||||||
$mail_attachments = $attachments->fetchAll();
|
$mail_attachments = $attachments->fetchAll();
|
||||||
|
|
||||||
|
// Helper to check previewable files
|
||||||
|
function isPreviewable($fileName) {
|
||||||
|
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||||
|
return in_array($ext, ['pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp']);
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<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">
|
||||||
@ -71,6 +100,13 @@ $mail_attachments = $attachments->fetchAll();
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<?= $error ?>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Mail Details -->
|
<!-- Mail Details -->
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
@ -183,6 +219,9 @@ $mail_attachments = $attachments->fetchAll();
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="POST" enctype="multipart/form-data" class="mb-4">
|
<form method="POST" enctype="multipart/form-data" class="mb-4">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
|
<label class="form-label small mb-1">اسم المرفق (يظهر في القائمة)</label>
|
||||||
|
<input type="text" name="display_name" class="form-control form-control-sm mb-2" placeholder="مثال: فاتورة، صورة العقد...">
|
||||||
|
<label class="form-label small mb-1">اختر الملف</label>
|
||||||
<input type="file" name="attachment" class="form-control form-control-sm" required>
|
<input type="file" name="attachment" class="form-control form-control-sm" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-sm btn-secondary w-100">رفع ملف</button>
|
<button type="submit" class="btn btn-sm btn-secondary w-100">رفع ملف</button>
|
||||||
@ -192,11 +231,30 @@ $mail_attachments = $attachments->fetchAll();
|
|||||||
<?php if ($mail_attachments): foreach ($mail_attachments as $a): ?>
|
<?php if ($mail_attachments): foreach ($mail_attachments as $a): ?>
|
||||||
<div class="list-group-item px-0">
|
<div class="list-group-item px-0">
|
||||||
<div class="d-flex w-100 justify-content-between align-items-center">
|
<div class="d-flex w-100 justify-content-between align-items-center">
|
||||||
<div class="text-truncate" style="max-width: 200px;">
|
<div class="text-truncate" style="max-width: 150px;">
|
||||||
<i class="fas fa-file me-2 text-muted"></i>
|
<i class="fas fa-file me-2 text-muted"></i>
|
||||||
<a href="<?= $a['file_path'] ?>" target="_blank" class="text-decoration-none small"><?= htmlspecialchars($a['file_name']) ?></a>
|
<a href="<?= $a['file_path'] ?>" target="_blank" class="text-decoration-none small">
|
||||||
|
<?= htmlspecialchars($a['display_name'] ?: $a['file_name']) ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="text-muted small me-2"><?= round($a['file_size'] / 1024, 1) ?> KB</span>
|
||||||
|
<?php if (isPreviewable($a['file_name'])): ?>
|
||||||
|
<button class="btn btn-link btn-sm p-0 text-primary preview-btn me-2"
|
||||||
|
data-file="<?= $a['file_path'] ?>"
|
||||||
|
data-name="<?= htmlspecialchars($a['display_name'] ?: $a['file_name']) ?>"
|
||||||
|
title="معاينة">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form method="POST" class="d-inline delete-attachment-form">
|
||||||
|
<input type="hidden" name="attachment_id" value="<?= $a['id'] ?>">
|
||||||
|
<input type="hidden" name="delete_attachment" value="1">
|
||||||
|
<button type="button" class="btn btn-link btn-sm p-0 text-danger delete-btn" title="حذف">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-muted small"><?= round($a['file_size'] / 1024, 1) ?> KB</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; else: ?>
|
<?php endforeach; else: ?>
|
||||||
@ -208,4 +266,83 @@ $mail_attachments = $attachments->fetchAll();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
<!-- Preview Modal -->
|
||||||
|
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="previewModalLabel">معاينة الملف</h5>
|
||||||
|
<button type="button" class="btn-close ms-0 me-auto" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body p-0 bg-dark d-flex align-items-center justify-content-center" style="min-height: 80vh;">
|
||||||
|
<div id="previewContainer" class="w-100 h-100 text-center">
|
||||||
|
<!-- Preview content will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<a id="downloadBtn" href="#" class="btn btn-primary" download>تحميل الملف</a>
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">إغلاق</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const previewModalEl = document.getElementById('previewModal');
|
||||||
|
let previewModal;
|
||||||
|
if (typeof bootstrap !== 'undefined') {
|
||||||
|
previewModal = new bootstrap.Modal(previewModalEl);
|
||||||
|
}
|
||||||
|
const previewContainer = document.getElementById('previewContainer');
|
||||||
|
const previewModalLabel = document.getElementById('previewModalLabel');
|
||||||
|
const downloadBtn = document.getElementById('downloadBtn');
|
||||||
|
|
||||||
|
document.querySelectorAll('.preview-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const filePath = this.getAttribute('data-file');
|
||||||
|
const fileName = this.getAttribute('data-name');
|
||||||
|
const ext = filePath.split('.').pop().toLowerCase();
|
||||||
|
|
||||||
|
previewModalLabel.textContent = 'معاينة: ' + fileName;
|
||||||
|
downloadBtn.href = filePath;
|
||||||
|
previewContainer.innerHTML = '';
|
||||||
|
|
||||||
|
if (ext === 'pdf') {
|
||||||
|
previewContainer.innerHTML = `<iframe src="${filePath}" width="100%" height="800px" style="border: none;"></iframe>`;
|
||||||
|
} else if (['png', 'jpg', 'jpeg', 'gif', 'webp'].includes(ext)) {
|
||||||
|
previewContainer.innerHTML = `<img src="${filePath}" class="img-fluid" style="max-height: 80vh;">`;
|
||||||
|
} else {
|
||||||
|
previewContainer.innerHTML = '<div class="text-white p-5">هذا النوع من الملفات غير مدعوم للمعاينة المباشرة</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previewModal) previewModal.show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
previewModalEl.addEventListener('hidden.bs.modal', function () {
|
||||||
|
previewContainer.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle Delete Confirmation
|
||||||
|
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const form = this.closest('form');
|
||||||
|
Swal.fire({
|
||||||
|
title: 'هل أنت متأكد؟',
|
||||||
|
text: "سيتم حذف المرفق نهائياً!",
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#d33',
|
||||||
|
cancelButtonColor: '#3085d6',
|
||||||
|
confirmButtonText: 'نعم، احذف',
|
||||||
|
cancelButtonText: 'إلغاء'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||||
Loading…
x
Reference in New Issue
Block a user