38808-vm/includes/header.php
2026-03-27 03:32:55 +00:00

603 lines
28 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');
}
// Determine active groups
$cp = basename($_SERVER['PHP_SELF']);
$mail_pages = ['inbound.php', 'outbound.php', 'internal_inbox.php', 'internal_outbox.php'];
$is_mail_open = in_array($cp, $mail_pages);
$acct_pages = ['accounting.php', 'trial_balance.php', 'balance_sheet.php', 'accounts.php'];
$is_acct_open = in_array($cp, $acct_pages);
$hr_pages = ['hr_dashboard.php', 'hr_employees.php', 'hr_attendance.php', 'hr_leaves.php', 'hr_holidays.php', 'hr_payroll.php', 'hr_reports.php'];
$is_hr_open = in_array($cp, $hr_pages);
$stock_pages = ['stock_dashboard.php', 'stock_items.php', 'stock_in.php', 'stock_out.php', 'stock_lending.php', 'stock_reports.php', 'stock_settings.php'];
$is_stock_open = in_array($cp, $stock_pages);
$report_pages = ['overdue_report.php'];
$is_report_open = in_array($cp, $report_pages);
$admin_pages = ['index.php', 'users.php', 'charity-settings.php'];
$is_admin_open = in_array($cp, $admin_pages);
?>
<!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; }
/* 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 setTheme(theme) {
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">
<!-- Dashboard -->
<li class="nav-item">
<a class="nav-link <?= ($cp == 'user_dashboard.php') ? 'active' : '' ?>" href="user_dashboard.php">
<i class="fas fa-tachometer-alt me-2"></i> لوحة التحكم
</a>
</li>
<!-- Mail Group -->
<?php if (canView('inbound') || canView('outbound') || canView('internal')): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_mail_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-mail" aria-expanded="<?= $is_mail_open ? 'true' : 'false' ?>">
<span class="group-content group-mail">
<i class="fas fa-envelope"></i> البريد
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_mail_open ? 'show' : '' ?>" id="menu-mail">
<ul class="nav flex-column">
<?php if (canView('inbound')): ?>
<li class="nav-item">
<a class="nav-link <?= ($cp == 'inbound.php' && !isset($_GET['my_tasks'])) ? 'active' : '' ?>" href="inbound.php">
البريد الوارد
</a>
</li>
<?php endif; ?>
<?php if (canView('outbound')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'outbound.php' ? 'active' : '' ?>" href="outbound.php">
البريد الصادر
</a>
</li>
<?php endif; ?>
<?php if (canView('internal')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'internal_inbox.php' ? 'active' : '' ?>" href="internal_inbox.php">
الوارد الداخلي
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $cp == 'internal_outbox.php' ? 'active' : '' ?>" href="internal_outbox.php">
الصادر الداخلي
</a>
</li>
<?php endif; ?>
</ul>
</div>
</li>
<?php endif; ?>
<!-- Accounting Group -->
<?php if (canView('accounting')): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_acct_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-acct" aria-expanded="<?= $is_acct_open ? 'true' : 'false' ?>">
<span class="group-content group-acct">
<i class="fas fa-calculator"></i> المحاسبة
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_acct_open ? 'show' : '' ?>" id="menu-acct">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link <?= $cp == 'accounting.php' ? 'active' : '' ?>" href="accounting.php">
المحاسبة العامة
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $cp == 'trial_balance.php' ? 'active' : '' ?>" href="trial_balance.php">
ميزان المراجعة
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $cp == 'balance_sheet.php' ? 'active' : '' ?>" href="balance_sheet.php">
الميزانية العمومية
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $cp == 'accounts.php' ? 'active' : '' ?>" href="accounts.php">
دليل الحسابات
</a>
</li>
</ul>
</div>
</li>
<?php endif; ?>
<!-- HR Group -->
<?php if (canView('hr_employees') || canView('hr_dashboard')): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_hr_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-hr" aria-expanded="<?= $is_hr_open ? 'true' : 'false' ?>">
<span class="group-content group-hr">
<i class="fas fa-users-cog"></i> الموارد البشرية
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_hr_open ? 'show' : '' ?>" id="menu-hr">
<ul class="nav flex-column">
<?php if (canView('hr_dashboard')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_dashboard.php' ? 'active' : '' ?>" href="hr_dashboard.php">
لوحة HR
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_employees')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_employees.php' ? 'active' : '' ?>" href="hr_employees.php">
الموظفين
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_attendance')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_attendance.php' ? 'active' : '' ?>" href="hr_attendance.php">
الحضور والانصراف
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_leaves')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_leaves.php' ? 'active' : '' ?>" href="hr_leaves.php">
الإجازات
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_attendance')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_holidays.php' ? 'active' : '' ?>" href="hr_holidays.php">
العطلات
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_payroll')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_payroll.php' ? 'active' : '' ?>" href="hr_payroll.php">
الرواتب
</a>
</li>
<?php endif; ?>
<?php if (canView('hr_reports')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'hr_reports.php' ? 'active' : '' ?>" href="hr_reports.php">
التقارير
</a>
</li>
<?php endif; ?>
</ul>
</div>
</li>
<?php endif; ?>
<!-- Stock Group -->
<?php if (canView('stock_dashboard') || canView('stock_items') || canView('stock_settings')): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_stock_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-stock" aria-expanded="<?= $is_stock_open ? 'true' : 'false' ?>">
<span class="group-content group-stock">
<i class="fas fa-boxes"></i> إدارة المخزون
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_stock_open ? 'show' : '' ?>" id="menu-stock">
<ul class="nav flex-column">
<?php if (canView('stock_dashboard')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_dashboard.php' ? 'active' : '' ?>" href="stock_dashboard.php">
لوحة التحكم
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_items')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_items.php' ? 'active' : '' ?>" href="stock_items.php">
الأصناف والمخزون
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_in')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_in.php' ? 'active' : '' ?>" href="stock_in.php">
توريد (وارد)
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_out')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_out.php' ? 'active' : '' ?>" href="stock_out.php">
صرف (صادر)
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_lending')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_lending.php' ? 'active' : '' ?>" href="stock_lending.php">
الإعارة
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_reports')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_reports.php' ? 'active' : '' ?>" href="stock_reports.php">
التقارير
</a>
</li>
<?php endif; ?>
<?php if (canView('stock_settings')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'stock_settings.php' ? 'active' : '' ?>" href="stock_settings.php">
إعدادات المخزون
</a>
</li>
<?php endif; ?>
</ul>
</div>
</li>
<?php endif; ?>
<!-- Reports Group -->
<?php if (canView('reports')): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_report_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-reports" aria-expanded="<?= $is_report_open ? 'true' : 'false' ?>">
<span class="group-content group-reports">
<i class="fas fa-chart-pie"></i> التقارير
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_report_open ? 'show' : '' ?>" id="menu-reports">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link <?= $cp == 'overdue_report.php' ? 'active' : '' ?>" href="overdue_report.php">
تقرير التأخير
</a>
</li>
</ul>
</div>
</li>
<?php endif; ?>
<!-- Admin Group -->
<?php if (canView('users') || canView('settings') || isAdmin()): ?>
<li class="nav-item">
<button class="sidebar-group-btn <?= $is_admin_open ? '' : 'collapsed' ?>" type="button" data-bs-toggle="collapse" data-bs-target="#menu-admin" aria-expanded="<?= $is_admin_open ? 'true' : 'false' ?>">
<span class="group-content group-admin">
<i class="fas fa-cogs"></i> الإدارة
</span>
<i class="fas fa-chevron-down arrow-icon"></i>
</button>
<div class="collapse <?= $is_admin_open ? 'show' : '' ?>" id="menu-admin">
<ul class="nav flex-column">
<?php if (isAdmin()): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'index.php' ? 'active' : '' ?>" href="index.php">
إحصائيات النظام
</a>
</li>
<?php endif; ?>
<?php if (canView('users')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'users.php' ? 'active' : '' ?>" href="users.php">
إدارة المستخدمين
</a>
</li>
<?php endif; ?>
<?php if (canView('settings')): ?>
<li class="nav-item">
<a class="nav-link <?= $cp == 'charity-settings.php' ? 'active' : '' ?>" href="charity-settings.php">
إعدادات النظام
</a>
</li>
<?php endif; ?>
</ul>
</div>
</li>
<?php endif; ?>
</ul>
<div class="mt-auto p-3 text-center opacity-50 small">
&copy; <?= 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 Dropdown -->
<div class="dropdown me-3">
<button class="btn btn-outline-secondary dropdown-toggle d-flex align-items-center gap-2" type="button" id="themeDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-palette"></i>
<span class="d-none d-md-inline">المظهر</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0" aria-labelledby="themeDropdown">
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('light')"><i class="fas fa-sun me-2 text-warning"></i> فاتح (Light)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('dark')"><i class="fas fa-moon me-2 text-dark"></i> داكن (Dark)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('midnight')"><i class="fas fa-star me-2 text-primary"></i> منتصف الليل (Midnight)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('forest')"><i class="fas fa-tree me-2 text-success"></i> غابة (Forest)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('ocean')"><i class="fas fa-water me-2 text-info"></i> محيط (Ocean)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('sunset')"><i class="fas fa-cloud-sun me-2 text-danger"></i> غروب (Sunset)</button></li>
<li><button class="dropdown-item d-flex align-items-center" onclick="setTheme('royal')"><i class="fas fa-crown me-2 text-secondary"></i> ملكي (Royal)</button></li>
</ul>
</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; ?>