434 lines
16 KiB
PHP
434 lines
16 KiB
PHP
<?php
|
|
ob_start(); error_reporting(E_ALL); ini_set("display_errors", 1);
|
|
session_start();
|
|
require_once __DIR__ . '/../db/config.php';
|
|
|
|
// --- Helper Functions (MUST BE DEFINED BEFORE settings.php) ---
|
|
|
|
function isLoggedIn() {
|
|
return isset($_SESSION['user_id']);
|
|
}
|
|
|
|
function isSuperAdmin() {
|
|
return isset($_SESSION['is_super_admin']) && $_SESSION['is_super_admin'] == 1;
|
|
}
|
|
|
|
function isAdmin() {
|
|
if (isSuperAdmin()) return true;
|
|
if (isset($_SESSION['user_role']) && strtolower($_SESSION['user_role']) === 'admin') return true;
|
|
if (isset($_SESSION['role']) && strtolower($_SESSION['role']) === 'admin') return true;
|
|
return false;
|
|
}
|
|
|
|
function redirect($path) {
|
|
if (!headers_sent()) {
|
|
header("Location: $path");
|
|
} else {
|
|
echo "<script>window.location.href='$path';</script>";
|
|
}
|
|
exit;
|
|
}
|
|
|
|
// Permission helpers
|
|
function canView($page = null) {
|
|
if (isAdmin()) return true;
|
|
if ($page) {
|
|
return $_SESSION['permissions'][$page]['view'] ?? false;
|
|
}
|
|
return $_SESSION['can_view'] ?? false;
|
|
}
|
|
|
|
function canAdd($page = null) {
|
|
if (isAdmin()) return true;
|
|
if ($page) {
|
|
return $_SESSION['permissions'][$page]['add'] ?? false;
|
|
}
|
|
return $_SESSION['can_add'] ?? false;
|
|
}
|
|
|
|
function canEdit($page = null) {
|
|
if (isAdmin()) return true;
|
|
if ($page) {
|
|
return $_SESSION['permissions'][$page]['edit'] ?? false;
|
|
}
|
|
return $_SESSION['can_edit'] ?? false;
|
|
}
|
|
|
|
function canDelete($page = null) {
|
|
if (isAdmin()) return true;
|
|
if ($page) {
|
|
return $_SESSION['permissions'][$page]['delete'] ?? false;
|
|
}
|
|
return $_SESSION['can_delete'] ?? false;
|
|
}
|
|
|
|
function canViewInternal() {
|
|
return canView('internal');
|
|
}
|
|
|
|
// Now load centralized settings (which may use the helpers above)
|
|
require_once __DIR__ . '/settings.php';
|
|
|
|
// Fetch user info (theme and permissions)
|
|
$user_theme = 'light';
|
|
$current_user = null;
|
|
if (isLoggedIn()) {
|
|
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
|
$stmt->execute([$_SESSION['user_id']]);
|
|
$current_user = $stmt->fetch();
|
|
|
|
if ($current_user) {
|
|
$user_theme = $current_user['theme'] ?: 'light';
|
|
$_SESSION['can_view'] = (bool)$current_user['can_view'];
|
|
$_SESSION['can_add'] = (bool)$current_user['can_add'];
|
|
$_SESSION['can_edit'] = (bool)$current_user['can_edit'];
|
|
$_SESSION['can_delete'] = (bool)$current_user['can_delete'];
|
|
$_SESSION['name'] = $current_user['full_name'] ?: $current_user['username'];
|
|
$_SESSION['user_role'] = strtolower($current_user['role']);
|
|
$_SESSION['role'] = strtolower($current_user['role']);
|
|
$_SESSION['is_super_admin'] = (int)$current_user['is_super_admin'];
|
|
|
|
// Load granular permissions
|
|
if (!isset($_SESSION['permissions']) || empty($_SESSION['permissions'])) {
|
|
$perm_stmt = db()->prepare("SELECT * FROM user_permissions WHERE user_id = ?");
|
|
$perm_stmt->execute([$_SESSION['user_id']]);
|
|
$perms = $perm_stmt->fetchAll();
|
|
$_SESSION['permissions'] = [];
|
|
foreach ($perms as $p) {
|
|
$_SESSION['permissions'][$p['page']] = [
|
|
'view' => (bool)$p['can_view'],
|
|
'add' => (bool)$p['can_add'],
|
|
'edit' => (bool)$p['can_edit'],
|
|
'delete' => (bool)$p['can_delete'],
|
|
];
|
|
}
|
|
}
|
|
} else {
|
|
// User not found in DB but session exists - clean up
|
|
session_destroy();
|
|
redirect('login.php');
|
|
}
|
|
}
|
|
|
|
// Auth Check (after fetch to ensure session is updated)
|
|
if (!isLoggedIn() && basename($_SERVER['PHP_SELF']) !== 'login.php' && basename($_SERVER['PHP_SELF']) !== 'forgot_password.php' && basename($_SERVER['PHP_SELF']) !== 'install.php') {
|
|
redirect('login.php');
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl" data-bs-theme="<?= $user_theme ?>">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= htmlspecialchars($sys_settings['site_name']) ?></title>
|
|
|
|
<!-- Bootstrap 5 RTL -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.rtl.min.css">
|
|
<!-- Font Awesome -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
|
<!-- Google Fonts - Cairo -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&display=swap" rel="stylesheet">
|
|
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time() ?>">
|
|
|
|
<?php if ($sys_settings['site_favicon']): ?>
|
|
<link rel="icon" type="image/x-icon" href="<?= $sys_settings['site_favicon'] ?>">
|
|
<?php endif; ?>
|
|
|
|
<style>
|
|
body {
|
|
font-family: 'Cairo', sans-serif;
|
|
background-color: var(--bs-body-bg);
|
|
}
|
|
.sidebar {
|
|
height: 100vh;
|
|
background-color: #212529;
|
|
color: #fff;
|
|
width: 250px;
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
z-index: 1000;
|
|
transition: all 0.3s;
|
|
overflow-y: auto;
|
|
scrollbar-width: thin;
|
|
scrollbar-color: rgba(255,255,255,0.2) transparent;
|
|
}
|
|
.sidebar::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
.sidebar::-webkit-scrollbar-thumb {
|
|
background-color: rgba(255,255,255,0.2);
|
|
border-radius: 10px;
|
|
}
|
|
.sidebar .nav-link {
|
|
color: rgba(255,255,255,0.7);
|
|
padding: 12px 20px;
|
|
border-radius: 0;
|
|
transition: all 0.2s;
|
|
}
|
|
.sidebar .nav-link:hover, .sidebar .nav-link.active {
|
|
color: #fff;
|
|
background-color: rgba(255,255,255,0.1);
|
|
}
|
|
.sidebar .nav-link.active {
|
|
border-right: 4px solid #0d6efd;
|
|
}
|
|
.logo-link:hover { opacity: 0.8; }
|
|
.sidebar-heading {
|
|
padding: 20px 20px 10px;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.1rem;
|
|
color: rgba(255,255,255,0.4);
|
|
}
|
|
.main-content {
|
|
margin-right: 250px;
|
|
padding: 20px;
|
|
min-height: 100vh;
|
|
}
|
|
.top-navbar {
|
|
margin-right: 250px;
|
|
background-color: var(--bs-tertiary-bg);
|
|
border-bottom: 1px solid var(--bs-border-color);
|
|
}
|
|
@media (max-width: 991.98px) {
|
|
.sidebar {
|
|
right: -250px;
|
|
}
|
|
.sidebar.show {
|
|
right: 0;
|
|
}
|
|
.main-content, .top-navbar {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
/* RTL Fixes for Bootstrap */
|
|
.ms-auto { margin-right: auto !important; margin-left: 0 !important; }
|
|
.me-auto { margin-left: auto !important; margin-right: 0 !important; }
|
|
|
|
/* Theme Switcher Styles */
|
|
.theme-switch-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.theme-switch {
|
|
display: inline-block;
|
|
height: 24px;
|
|
position: relative;
|
|
width: 48px;
|
|
}
|
|
.theme-switch input { display: none; }
|
|
.slider {
|
|
background-color: #ccc;
|
|
bottom: 0;
|
|
cursor: pointer;
|
|
left: 0;
|
|
position: absolute;
|
|
right: 0;
|
|
top: 0;
|
|
transition: .4s;
|
|
border-radius: 34px;
|
|
}
|
|
.slider:before {
|
|
background-color: #fff;
|
|
bottom: 4px;
|
|
content: "";
|
|
height: 16px;
|
|
left: 4px;
|
|
position: absolute;
|
|
transition: .4s;
|
|
width: 16px;
|
|
border-radius: 50%;
|
|
}
|
|
input:checked + .slider { background-color: #0d6efd; }
|
|
input:checked + .slider:before { transform: translateX(24px); }
|
|
.slider .fa-sun {
|
|
position: absolute;
|
|
left: 6px;
|
|
top: 4px;
|
|
font-size: 12px;
|
|
color: #ffc107;
|
|
opacity: 1;
|
|
transition: .4s;
|
|
}
|
|
.slider .fa-moon {
|
|
position: absolute;
|
|
right: 6px;
|
|
top: 4px;
|
|
font-size: 12px;
|
|
color: #f8f9fa;
|
|
opacity: 0;
|
|
transition: .4s;
|
|
}
|
|
input:checked + .slider .fa-sun { opacity: 0; }
|
|
input:checked + .slider .fa-moon { opacity: 1; }
|
|
|
|
/* RTL specific tweaks */
|
|
[dir="rtl"] .dropdown-menu { text-align: right; }
|
|
[dir="rtl"] .ms-2 { margin-right: 0.5rem !important; margin-left: 0 !important; }
|
|
[dir="rtl"] .me-2 { margin-left: 0.5rem !important; margin-right: 0 !important; }
|
|
[dir="rtl"] .me-1 { margin-left: 0.25rem !important; margin-right: 0 !important; }
|
|
</style>
|
|
<script>
|
|
function toggleSidebar() {
|
|
document.getElementById('sidebar').classList.toggle('show');
|
|
}
|
|
function toggleTheme(checkbox) {
|
|
const theme = checkbox.checked ? 'dark' : 'light';
|
|
document.documentElement.setAttribute('data-bs-theme', theme);
|
|
fetch('api/update_theme.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ theme: theme })
|
|
});
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
|
|
<?php if (isLoggedIn()): ?>
|
|
<!-- Sidebar -->
|
|
<div class="sidebar d-flex flex-column" id="sidebar">
|
|
<div class="p-3 text-center border-bottom border-secondary">
|
|
<a href="user_dashboard.php" class="text-decoration-none text-white d-block logo-link">
|
|
<?php if (!empty($sys_settings['site_logo'])): ?>
|
|
<img src="<?= $sys_settings['site_logo'] ?>" alt="Logo" class="img-fluid mb-2" style="max-height: 50px;">
|
|
<?php endif; ?>
|
|
<h5 class="mb-0 fw-bold"><?= htmlspecialchars($sys_settings['site_name']) ?></h5>
|
|
</a>
|
|
</div>
|
|
|
|
<ul class="nav flex-column mt-3 mb-4">
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'user_dashboard.php') ? 'active' : '' ?>" href="user_dashboard.php">
|
|
<i class="fas fa-tachometer-alt me-2"></i> لوحة التحكم
|
|
</a>
|
|
</li>
|
|
|
|
<?php if (canView('inbound') || canView('outbound')): ?>
|
|
<div class="sidebar-heading">البريد الخارجي</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('inbound')): ?>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'inbound.php' && !isset($_GET['my_tasks'])) ? 'active' : '' ?>" href="inbound.php">
|
|
<i class="fas fa-download me-2"></i> البريد الوارد
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('outbound')): ?>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'outbound.php' ? 'active' : '' ?>" href="outbound.php">
|
|
<i class="fas fa-upload me-2"></i> البريد الصادر
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('internal')): ?>
|
|
<div class="sidebar-heading">البريد الداخلي</div>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'internal_inbox.php' ? 'active' : '' ?>" href="internal_inbox.php">
|
|
<i class="fas fa-inbox me-2"></i> الوارد الداخلي
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'internal_outbox.php' ? 'active' : '' ?>" href="internal_outbox.php">
|
|
<i class="fas fa-paper-plane me-2"></i> الصادر الداخلي
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('reports')): ?>
|
|
<div class="sidebar-heading">التقارير</div>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'overdue_report.php' ? 'active' : '' ?>" href="overdue_report.php">
|
|
<i class="fas fa-exclamation-circle me-2"></i> تقرير التأخير
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('users') || canView('settings') || isAdmin()): ?>
|
|
<div class="sidebar-heading">الإدارة</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (isAdmin()): ?>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'index.php' ? 'active' : '' ?>" href="index.php">
|
|
<i class="fas fa-chart-line me-2"></i> إحصائيات النظام
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('users')): ?>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : '' ?>" href="users.php">
|
|
<i class="fas fa-users me-2"></i> إدارة المستخدمين
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
|
|
<?php if (canView('settings')): ?>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'charity-settings.php' ? 'active' : '' ?>" href="charity-settings.php">
|
|
<i class="fas fa-cog me-2"></i> إعدادات النظام
|
|
</a>
|
|
</li>
|
|
<?php endif; ?>
|
|
</ul>
|
|
|
|
<div class="mt-auto p-3 text-center opacity-50 small">
|
|
© <?= date('Y') ?> <?= htmlspecialchars($sys_settings['site_name']) ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Top Navbar -->
|
|
<nav class="navbar navbar-expand-lg top-navbar sticky-top p-0 shadow-sm">
|
|
<div class="container-fluid px-3">
|
|
<button class="btn d-lg-none" type="button" onclick="toggleSidebar()">
|
|
<i class="fas fa-bars"></i>
|
|
</button>
|
|
|
|
<div class="ms-auto d-flex align-items-center">
|
|
<!-- Theme Switcher -->
|
|
<div class="theme-switch-wrapper me-3">
|
|
<label class="theme-switch" for="checkbox">
|
|
<input type="checkbox" id="checkbox" <?= $user_theme === 'dark' ? 'checked' : '' ?> onchange="toggleTheme(this)">
|
|
<div class="slider">
|
|
<i class="fas fa-sun"></i>
|
|
<i class="fas fa-moon"></i>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="dropdown">
|
|
<button class="btn d-flex align-items-center dropdown-toggle border-0" type="button" id="userMenu" data-bs-toggle="dropdown" aria-expanded="false">
|
|
<div class="text-end me-2 d-none d-md-block">
|
|
<div class="fw-bold small"><?= htmlspecialchars($_SESSION['name'] ?? 'المستخدم') ?></div>
|
|
<div class="text-muted" style="font-size: 0.7rem;"><?= ucfirst($_SESSION['user_role'] ?? 'موظف') ?></div>
|
|
</div>
|
|
<?php if (!empty($current_user['profile_image'])): ?>
|
|
<img src="<?= $current_user['profile_image'] ?>" alt="Profile" class="rounded-circle" width="35" height="35" style="object-fit: cover;">
|
|
<?php else: ?>
|
|
<div class="rounded-circle bg-primary bg-opacity-10 d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">
|
|
<i class="fas fa-user text-primary"></i>
|
|
</div>
|
|
<?php endif; ?>
|
|
</button>
|
|
<ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="userMenu">
|
|
<li><a class="dropdown-item" href="profile.php"><i class="fas fa-user-circle me-2 text-muted"></i> ملفي الشخصي</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item text-danger" href="logout.php"><i class="fas fa-sign-out-alt me-2"></i> تسجيل الخروج</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<?php endif; ?>
|