diff --git a/application_detail.php b/application_detail.php
new file mode 100644
index 0000000..dab87de
--- /dev/null
+++ b/application_detail.php
@@ -0,0 +1,149 @@
+ 0 ? get_application($applicationId) : null;
+
+if (!$application) {
+ http_response_code(404);
+ render_page_start('طلب غير موجود', 'applications', 'لم يتم العثور على طلب فتح المركز المطلوب.');
+ render_flash($flash);
+ ?>
+
+
+
+
الطلب غير موجود
+
تحقق من رقم المرجع أو ارجع إلى لوحة الطلبات.
+
العودة إلى القائمة
+
+
+
+ ['min_range' => 0, 'max_range' => 100],
+ ]);
+
+ if (($_POST['evaluation_score'] ?? '') !== '' && $evaluationScore === false) {
+ $reviewErrors['evaluation_score'] = 'أدخل درجة بين 0 و100.';
+ }
+
+ if ($reviewErrors === []) {
+ try {
+ update_application_review($applicationId, $status, $adminNotes, $evaluationScore === false ? null : $evaluationScore);
+ set_flash('success', 'تم تحديث حالة الطلب وملاحظات التقييم بنجاح.');
+ header('Location: application_detail.php?id=' . urlencode((string) $applicationId));
+ exit;
+ } catch (Throwable $exception) {
+ $reviewErrors['form'] = 'تعذر حفظ التحديث الآن. حاول مرة أخرى.';
+ }
+ }
+}
+
+$application = get_application($applicationId);
+$statusMeta = status_meta((string) $application['status']);
+
+render_page_start('تفاصيل الطلب #' . $applicationId, 'applications', 'عرض تفصيلي لطلب فتح المركز مع نموذج المراجعة للمشرف العام.');
+render_flash($flash);
+?>
+
+
+
+
+
+
+
+
مرجع الطلب #= e((string) $application['id']) ?>
+
= e((string) $application['center_name']) ?>
+
مقدم الطلب: = e((string) $application['director_name']) ?> — = e((string) $application['city']) ?>
+
+ = status_badge((string) $application['status']) ?>
+
+
+
+
نوع المركز = e((string) $application['center_type']) ?>
+
الفئة المستهدفة = e((string) $application['gender_scope']) ?>
+
رقم الهاتف = e((string) $application['phone']) ?>
+
البريد الإلكتروني = e((string) $application['email']) ?>
+
السعة المتوقعة = e((string) $application['expected_students']) ?> طالب
+
فترة البرنامج = e((string) $application['start_date']) ?> — = e((string) $application['end_date']) ?>
+
+
+
+
ملخص البرنامج والاحتياجات
+
= nl2br(e((string) ($application['notes'] ?: 'لا توجد ملاحظات إضافية.'))) ?>
+
+
+
+
+
سجل المراجعة
+
+
+
تم استلام الطلب
+
أُرسل الطلب بتاريخ = e((string) $application['submitted_at']) ?>.
+
+
+
الحالة الحالية: = e($statusMeta['label']) ?>
+
آخر تحديث بتاريخ = e((string) $application['updated_at']) ?>.
+
+
+
ملاحظات المشرف العام
+
= nl2br(e((string) ($application['admin_notes'] ?: 'لم تُسجل ملاحظات بعد.'))) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/applications.php b/applications.php
new file mode 100644
index 0000000..fbc7e35
--- /dev/null
+++ b/applications.php
@@ -0,0 +1,88 @@
+ 'الكل'] + array_map(fn ($meta) => $meta['label'], status_map());
+
+render_page_start('لوحة الطلبات', 'applications', 'قائمة موحدة لطلبات فتح المراكز الصيفية مع فلترة حسب حالة المراجعة.');
+render_flash($flash);
+?>
+
+
+
+
+
+
لوحة طلبات فتح المراكز
+
واجهة المشرف العام لمراجعة جميع الطلبات، فرزها بالحالة، ثم الانتقال إلى التفاصيل لاتخاذ القرار.
+
+
+
+
+
+
+
+
+
+
لا توجد طلبات ضمن هذا التصنيف.
+
ابدأ بإنشاء أول طلب فتح مركز ليظهر هنا فوراً.
+
إنشاء طلب
+
+
+
+
+
+
+ المرجع
+ المركز
+ المدينة
+ المدير
+ الفترة
+ الحالة
+ التقييم
+
+
+
+
+
+ #= e((string) $application['id']) ?>
+
+ = e((string) $application['center_name']) ?>
+ سعة متوقعة: = e((string) $application['expected_students']) ?> طالب
+
+ = e((string) $application['city']) ?>
+
+ = e((string) $application['director_name']) ?>
+ = e((string) $application['phone']) ?>
+
+
+ = e((string) $application['start_date']) ?>
+ حتى = e((string) $application['end_date']) ?>
+
+ = status_badge((string) $application['status']) ?>
+ = $application['evaluation_score'] !== null ? e((string) $application['evaluation_score']) . '%' : '—' ?>
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/css/custom.css b/assets/css/custom.css
index 789132e..8261a74 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,403 +1,571 @@
+ :root {
+ --bg: #f3f4f6;
+ --surface: #ffffff;
+ --surface-muted: #f8fafc;
+ --border: #d6dbe3;
+ --border-strong: #c1c8d2;
+ --text: #0f172a;
+ --muted: #475569;
+ --primary: #111827;
+ --accent: #0f766e;
+ --accent-soft: #ecfdf5;
+ --success: #166534;
+ --warning: #92400e;
+ --danger: #b91c1c;
+ --shadow: 0 10px 30px rgba(15, 23, 42, 0.05);
+ --radius-sm: 10px;
+ --radius-md: 14px;
+ --radius-lg: 18px;
+ --font-ui: "IBM Plex Sans Arabic", "Segoe UI", Tahoma, Arial, sans-serif;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
body {
- background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
- background-size: 400% 400%;
- animation: gradient 15s ease infinite;
- color: #212529;
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
- font-size: 14px;
margin: 0;
+ background: var(--bg);
+ color: var(--text);
+ font-family: var(--font-ui);
+ font-weight: 400;
+ line-height: 1.7;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+body,
+.form-control,
+.form-select,
+.btn,
+.table {
+ font-size: 0.96rem;
+}
+
+input,
+select,
+textarea,
+button {
+ font: inherit;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.brand-title,
+.hero-title,
+.stat-label,
+.section-title,
+.footer-title,
+.timeline-title,
+.empty-title {
+ font-family: var(--font-ui);
+ letter-spacing: 0;
+}
+
+::selection {
+ background: rgba(15, 118, 110, 0.18);
+}
+
+.app-shell {
min-height: 100vh;
}
-.main-wrapper {
- display: flex;
+.site-header,
+.site-footer {
+ background: rgba(255, 255, 255, 0.92);
+ backdrop-filter: blur(8px);
+}
+
+.site-header {
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+}
+
+.navbar-brand,
+.nav-link {
+ color: var(--text);
+}
+
+.navbar-brand:hover,
+.nav-link:hover {
+ color: var(--primary);
+}
+
+.nav-link {
+ border-radius: 999px;
+ padding: 0.55rem 0.9rem;
+ color: var(--muted);
+ font-weight: 500;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.nav-link.active,
+.nav-link:hover {
+ background: #eef2f7;
+ color: var(--primary);
+}
+
+.brand-mark {
+ text-decoration: none;
+}
+
+.brand-badge {
+ width: 2.4rem;
+ height: 2.4rem;
+ display: inline-flex;
align-items: center;
justify-content: center;
- min-height: 100vh;
- width: 100%;
- padding: 20px;
- box-sizing: border-box;
- position: relative;
- z-index: 1;
-}
-
-@keyframes gradient {
- 0% {
- background-position: 0% 50%;
- }
- 50% {
- background-position: 100% 50%;
- }
- 100% {
- background-position: 0% 50%;
- }
-}
-
-.chat-container {
- width: 100%;
- max-width: 600px;
- background: rgba(255, 255, 255, 0.85);
- border: 1px solid rgba(255, 255, 255, 0.3);
- border-radius: 20px;
- display: flex;
- flex-direction: column;
- height: 85vh;
- box-shadow: 0 20px 40px rgba(0,0,0,0.2);
- backdrop-filter: blur(15px);
- -webkit-backdrop-filter: blur(15px);
- overflow: hidden;
-}
-
-.chat-header {
- padding: 1.5rem;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
- background: rgba(255, 255, 255, 0.5);
+ border-radius: 12px;
+ background: var(--primary);
+ color: #fff;
font-weight: 700;
- font-size: 1.1rem;
- display: flex;
- justify-content: space-between;
- align-items: center;
}
-.chat-messages {
- flex: 1;
- overflow-y: auto;
- padding: 1.5rem;
+.brand-title {
+ font-weight: 700;
+ font-size: 1.02rem;
+}
+
+.brand-subtitle,
+.footer-meta,
+.section-copy,
+.hero-copy,
+.text-muted {
+ color: var(--muted) !important;
+}
+
+.brand-subtitle {
+ font-size: 0.82rem;
+ font-weight: 500;
+}
+
+.header-chip,
+.eyebrow,
+.pill-count {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ border: 1px solid var(--border);
+ border-radius: 999px;
+ background: #fff;
+ color: var(--muted);
+ padding: 0.38rem 0.7rem;
+ font-size: 0.78rem;
+ font-weight: 500;
+}
+
+.container-xxl {
+ max-width: 1240px;
+}
+
+.hero-section {
+ padding-top: 2rem;
+}
+
+.hero-title {
+ font-size: clamp(2.05rem, 2.9vw, 3.1rem);
+ line-height: 1.3;
+ font-weight: 700;
+ margin: 0;
+ max-width: 15ch;
+}
+
+.hero-copy {
+ max-width: 58ch;
+ font-size: 1rem;
+}
+
+.hero-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.7rem;
+ color: var(--muted);
+ font-size: 0.84rem;
+}
+
+.hero-meta span {
+ padding: 0.45rem 0.75rem;
+ background: var(--surface-muted);
+ border: 1px solid var(--border);
+ border-radius: 999px;
+}
+
+.app-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow);
+ padding: 1.35rem;
+}
+
+.compact-card,
+.sidebar-card {
+ padding: 1.1rem;
+}
+
+.hero-card {
+ padding: 1.7rem;
+}
+
+.form-card,
+.detail-card {
+ padding: 1.4rem;
+}
+
+.stat-card {
display: flex;
flex-direction: column;
- gap: 1.25rem;
+ gap: 0.4rem;
+ min-height: 160px;
}
-/* Custom Scrollbar */
-::-webkit-scrollbar {
- width: 6px;
+.stat-label,
+.section-title,
+.footer-title,
+.timeline-title,
+.empty-title {
+ font-weight: 700;
}
-::-webkit-scrollbar-track {
- background: transparent;
-}
-
-::-webkit-scrollbar-thumb {
- background: rgba(255, 255, 255, 0.3);
- border-radius: 10px;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: rgba(255, 255, 255, 0.5);
-}
-
-.message {
- max-width: 85%;
- padding: 0.85rem 1.1rem;
- border-radius: 16px;
- line-height: 1.5;
- font-size: 0.95rem;
- box-shadow: 0 4px 15px rgba(0,0,0,0.05);
- animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-}
-
-@keyframes fadeIn {
- from { opacity: 0; transform: translateY(20px) scale(0.95); }
- to { opacity: 1; transform: translateY(0) scale(1); }
-}
-
-.message.visitor {
- align-self: flex-end;
- background: linear-gradient(135deg, #212529 0%, #343a40 100%);
- color: #fff;
- border-bottom-right-radius: 4px;
-}
-
-.message.bot {
- align-self: flex-start;
- background: #ffffff;
- color: #212529;
- border-bottom-left-radius: 4px;
-}
-
-.chat-input-area {
- padding: 1.25rem;
- background: rgba(255, 255, 255, 0.5);
- border-top: 1px solid rgba(0, 0, 0, 0.05);
-}
-
-.chat-input-area form {
+.section-head {
display: flex;
- gap: 0.75rem;
-}
-
-.chat-input-area input {
- flex: 1;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- padding: 0.75rem 1rem;
- outline: none;
- background: rgba(255, 255, 255, 0.9);
- transition: all 0.3s ease;
-}
-
-.chat-input-area input:focus {
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2);
-}
-
-.chat-input-area button {
- background: #212529;
- color: #fff;
- border: none;
- padding: 0.75rem 1.5rem;
- border-radius: 12px;
- cursor: pointer;
- font-weight: 600;
- transition: all 0.3s ease;
-}
-
-.chat-input-area button:hover {
- background: #000;
- transform: translateY(-2px);
- box-shadow: 0 5px 15px rgba(0,0,0,0.2);
-}
-
-/* Background Animations */
-.bg-animations {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- overflow: hidden;
- pointer-events: none;
-}
-
-.blob {
- position: absolute;
- width: 500px;
- height: 500px;
- background: rgba(255, 255, 255, 0.2);
- border-radius: 50%;
- filter: blur(80px);
- animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
-}
-
-.blob-1 {
- top: -10%;
- left: -10%;
- background: rgba(238, 119, 82, 0.4);
-}
-
-.blob-2 {
- bottom: -10%;
- right: -10%;
- background: rgba(35, 166, 213, 0.4);
- animation-delay: -7s;
- width: 600px;
- height: 600px;
-}
-
-.blob-3 {
- top: 40%;
- left: 30%;
- background: rgba(231, 60, 126, 0.3);
- animation-delay: -14s;
- width: 450px;
- height: 450px;
-}
-
-@keyframes move {
- 0% { transform: translate(0, 0) rotate(0deg) scale(1); }
- 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); }
- 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); }
- 100% { transform: translate(0, 0) rotate(360deg) scale(1); }
-}
-
-.header-link {
- font-size: 14px;
- color: #fff;
- text-decoration: none;
- background: rgba(0, 0, 0, 0.2);
- padding: 0.5rem 1rem;
- border-radius: 8px;
- transition: all 0.3s ease;
-}
-
-.header-link:hover {
- background: rgba(0, 0, 0, 0.4);
- text-decoration: none;
-}
-
-/* Admin Styles */
-.admin-container {
- max-width: 900px;
- margin: 3rem auto;
- padding: 2.5rem;
- background: rgba(255, 255, 255, 0.85);
- backdrop-filter: blur(20px);
- -webkit-backdrop-filter: blur(20px);
- border-radius: 24px;
- box-shadow: 0 20px 50px rgba(0,0,0,0.15);
- border: 1px solid rgba(255, 255, 255, 0.4);
- position: relative;
- z-index: 1;
-}
-
-.admin-container h1 {
- margin-top: 0;
- color: #212529;
- font-weight: 800;
-}
-
-.table {
- width: 100%;
- border-collapse: separate;
- border-spacing: 0 8px;
- margin-top: 1.5rem;
-}
-
-.table th {
- background: transparent;
- border: none;
- padding: 1rem;
- color: #6c757d;
- font-weight: 600;
- text-transform: uppercase;
- font-size: 0.75rem;
- letter-spacing: 1px;
-}
-
-.table td {
- background: #fff;
- padding: 1rem;
- border: none;
-}
-
-.table tr td:first-child { border-radius: 12px 0 0 12px; }
-.table tr td:last-child { border-radius: 0 12px 12px 0; }
-
-.form-group {
- margin-bottom: 1.25rem;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 0.5rem;
- font-weight: 600;
- font-size: 0.9rem;
-}
-
-.form-control {
- width: 100%;
- padding: 0.75rem 1rem;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 12px;
- background: #fff;
- transition: all 0.3s ease;
- box-sizing: border-box;
-}
-
-.form-control:focus {
- outline: none;
- border-color: #23a6d5;
- box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1);
-}
-
-.header-container {
- display: flex;
- justify-content: space-between;
align-items: center;
-}
-
-.header-links {
- display: flex;
+ justify-content: space-between;
gap: 1rem;
}
-.admin-card {
- background: rgba(255, 255, 255, 0.6);
- padding: 2rem;
- border-radius: 20px;
- border: 1px solid rgba(255, 255, 255, 0.5);
- margin-bottom: 2.5rem;
- box-shadow: 0 10px 30px rgba(0,0,0,0.05);
+.section-title {
+ font-size: 1.08rem;
}
-.admin-card h3 {
- margin-top: 0;
- margin-bottom: 1.5rem;
+.small-title {
+ font-size: 0.96rem;
+}
+
+.stat-value {
+ font-size: clamp(1.8rem, 3vw, 2.4rem);
+ font-weight: 700;
+ color: var(--primary);
+ letter-spacing: -0.02em;
+}
+
+.stat-note,
+.workflow-list,
+.check-list,
+.timeline-copy,
+.summary-row span {
+ color: var(--muted);
+}
+
+.module-list {
+ display: grid;
+ gap: 0.9rem;
+}
+
+.module-item {
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ background: var(--surface-muted);
+ padding: 1rem;
+}
+
+.module-item h2 {
+ font-size: 0.98rem;
+ margin: 0 0 0.35rem;
+}
+
+.module-item p,
+.summary-row,
+.detail-item span,
+.detail-item strong,
+.timeline-copy,
+.notes-block p {
+ margin: 0;
+}
+
+.workflow-list,
+.check-list {
+ padding-right: 1.2rem;
+ margin: 0;
+ display: grid;
+ gap: 0.65rem;
+}
+
+.filter-pills {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.65rem;
+}
+
+.filter-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.45rem;
+ border: 1px solid var(--border);
+ border-radius: 999px;
+ padding: 0.55rem 0.8rem;
+ background: #fff;
+ color: var(--muted);
+ text-decoration: none;
+ font-weight: 500;
+}
+
+.filter-pill.active,
+.filter-pill:hover {
+ color: var(--primary);
+ background: #eef2f7;
+ border-color: var(--border-strong);
+}
+
+.pill-count {
+ padding: 0.2rem 0.5rem;
+ background: transparent;
+}
+
+.app-table {
+ --bs-table-bg: transparent;
+ --bs-table-border-color: #e6e8ee;
+ margin: 0;
+}
+
+.app-table thead th {
+ font-size: 0.8rem;
+ font-weight: 600;
+ letter-spacing: 0;
+ color: #64748b;
+ white-space: nowrap;
+ border-bottom-width: 1px;
+}
+
+.app-table tbody td {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+ vertical-align: middle;
+}
+
+.table-link {
+ color: var(--primary);
+ text-decoration: none;
font-weight: 700;
}
-.btn-delete {
- background: #dc3545;
- color: white;
- border: none;
- padding: 0.25rem 0.5rem;
- border-radius: 4px;
- cursor: pointer;
+.table-link:hover {
+ text-decoration: underline;
}
-.btn-add {
- background: #212529;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 4px;
- cursor: pointer;
- margin-top: 1rem;
-}
-
-.btn-save {
- background: #0088cc;
- color: white;
- border: none;
- padding: 0.8rem 1.5rem;
- border-radius: 12px;
- cursor: pointer;
+.status-badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 999px;
+ padding: 0.35rem 0.7rem;
+ font-size: 0.78rem;
font-weight: 600;
- width: 100%;
- transition: all 0.3s ease;
+ border: 1px solid transparent;
}
-.webhook-url {
- font-size: 0.85em;
- color: #555;
- margin-top: 0.5rem;
+.status-submitted {
+ background: #eff6ff;
+ color: #1d4ed8;
+ border-color: #bfdbfe;
}
-.history-table-container {
- overflow-x: auto;
- background: rgba(255, 255, 255, 0.4);
- padding: 1rem;
+.status-review {
+ background: #fff7ed;
+ color: var(--warning);
+ border-color: #fed7aa;
+}
+
+.status-approved {
+ background: #ecfdf5;
+ color: var(--success);
+ border-color: #bbf7d0;
+}
+
+.status-rejected {
+ background: #fef2f2;
+ color: var(--danger);
+ border-color: #fecaca;
+}
+
+.status-muted {
+ background: #f8fafc;
+ color: var(--muted);
+ border-color: var(--border);
+}
+
+.form-label {
+ font-weight: 600;
+ margin-bottom: 0.45rem;
+}
+
+.form-control,
+.form-select {
+ min-height: 2.9rem;
+ border-color: var(--border-strong);
border-radius: 12px;
- border: 1px solid rgba(255, 255, 255, 0.3);
+ padding: 0.7rem 0.9rem;
+ background-color: #fff;
}
-.history-table {
- width: 100%;
+textarea.form-control {
+ min-height: 120px;
}
-.history-table-time {
- width: 15%;
- white-space: nowrap;
- font-size: 0.85em;
- color: #555;
+.form-control:focus,
+.form-select:focus,
+.btn:focus,
+.nav-link:focus,
+.filter-pill:focus {
+ border-color: rgba(15, 118, 110, 0.45);
+ box-shadow: 0 0 0 0.18rem rgba(15, 118, 110, 0.13);
}
-.history-table-user {
- width: 35%;
- background: rgba(255, 255, 255, 0.3);
- border-radius: 8px;
- padding: 8px;
+.btn {
+ border-radius: 12px;
+ padding: 0.68rem 1rem;
+ font-weight: 600;
}
-.history-table-ai {
- width: 50%;
- background: rgba(255, 255, 255, 0.5);
- border-radius: 8px;
- padding: 8px;
+.btn-dark {
+ background: var(--primary);
+ border-color: var(--primary);
}
-.no-messages {
- text-align: center;
- color: #777;
-}
\ No newline at end of file
+.btn-dark:hover,
+.btn-dark:focus {
+ background: #0b1220;
+ border-color: #0b1220;
+}
+
+.btn-outline-secondary {
+ color: var(--primary);
+ border-color: var(--border-strong);
+}
+
+.btn-outline-secondary:hover {
+ background: #eef2f7;
+ border-color: var(--border-strong);
+ color: var(--primary);
+}
+
+.detail-grid .detail-item,
+.summary-row,
+.notes-block,
+.timeline-item {
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ background: var(--surface-muted);
+ padding: 0.95rem 1rem;
+}
+
+.detail-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ height: 100%;
+}
+
+.detail-item span {
+ font-size: 0.84rem;
+ color: var(--muted);
+}
+
+.detail-item strong,
+.summary-row strong {
+ font-size: 0.94rem;
+ font-weight: 600;
+}
+
+.timeline-list,
+.summary-stack {
+ display: grid;
+ gap: 0.75rem;
+}
+
+.timeline-item {
+ position: relative;
+}
+
+.timeline-item::before {
+ content: "";
+ position: absolute;
+ inset-inline-start: 0;
+ top: 0;
+ bottom: 0;
+ width: 3px;
+ border-radius: 999px;
+ background: var(--accent);
+ opacity: 0.16;
+}
+
+.notes-block {
+ line-height: 1.85;
+}
+
+.summary-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+}
+
+.empty-state {
+ border: 1px dashed var(--border-strong);
+ border-radius: var(--radius-md);
+ background: var(--surface-muted);
+}
+
+.toast {
+ border-radius: 14px;
+ box-shadow: var(--shadow);
+}
+
+.alert {
+ border-radius: 14px;
+}
+
+.footer-title {
+ font-size: 0.98rem;
+}
+
+@media (max-width: 991.98px) {
+ .site-header {
+ position: static;
+ }
+
+ .hero-card,
+ .app-card,
+ .form-card,
+ .detail-card {
+ padding: 1rem;
+ }
+
+ .header-actions {
+ margin-top: 1rem;
+ }
+}
+
+
+.link-card {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: 0.8rem;
+ min-height: 220px;
+}
+
+.link-card p {
+ margin: 0;
+}
diff --git a/assets/js/main.js b/assets/js/main.js
index d349598..cba6d93 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,39 +1,12 @@
document.addEventListener('DOMContentLoaded', () => {
- const chatForm = document.getElementById('chat-form');
- const chatInput = document.getElementById('chat-input');
- const chatMessages = document.getElementById('chat-messages');
+ const toastElement = document.getElementById('appToast');
+ if (toastElement && window.bootstrap) {
+ const toast = new bootstrap.Toast(toastElement);
+ toast.show();
+ }
- const appendMessage = (text, sender) => {
- const msgDiv = document.createElement('div');
- msgDiv.classList.add('message', sender);
- msgDiv.textContent = text;
- chatMessages.appendChild(msgDiv);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- };
-
- chatForm.addEventListener('submit', async (e) => {
- e.preventDefault();
- const message = chatInput.value.trim();
- if (!message) return;
-
- appendMessage(message, 'visitor');
- chatInput.value = '';
-
- try {
- const response = await fetch('api/chat.php', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ message })
- });
- const data = await response.json();
-
- // Artificial delay for realism
- setTimeout(() => {
- appendMessage(data.reply, 'bot');
- }, 500);
- } catch (error) {
- console.error('Error:', error);
- appendMessage("Sorry, something went wrong. Please try again.", 'bot');
- }
- });
+ const invalidField = document.querySelector('.is-invalid');
+ if (invalidField) {
+ invalidField.focus({ preventScroll: false });
+ }
});
diff --git a/center_application.php b/center_application.php
new file mode 100644
index 0000000..8631a6d
--- /dev/null
+++ b/center_application.php
@@ -0,0 +1,147 @@
+
+
+
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000..2fbdc42
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
لوحة القيادة التشغيلية
+
هذه الصفحة مخصصة للمتابعة اليومية للمشرف العام: مؤشرات سريعة، آخر الطلبات، وروابط التحرك المباشر.
+
+
+
+
+
+
+
+
+
إجمالي الطلبات
+
= e($stats['all']) ?>
+
جميع طلبات فتح المراكز
+
+
+
+
+
قيد الاستلام
+
= e($stats['submitted']) ?>
+
بحاجة إلى بدء المراجعة
+
+
+
+
+
تحت المراجعة
+
= e($stats['under_review']) ?>
+
نشطة داخل مسار التقييم
+
+
+
+
+
معتمد
+
= e($stats['approved']) ?>
+
جاهز لاستقبال الطلاب
+
+
+
+
+
+
+
+
+
+
+
+
+ المرجع
+ المركز
+ المدينة
+ الحالة
+ السعة
+
+
+
+
+
+ #= e((string) $application['id']) ?>
+
+ = e((string) $application['center_name']) ?>
+ = e((string) $application['director_name']) ?>
+
+ = e((string) $application['city']) ?>
+ = status_badge((string) $application['status']) ?>
+ = e((string) $application['expected_students']) ?> طالب
+
+
+
+
+
+
+
+
+
+
إجراءات سريعة
+
+
+ بدء طلب جديد
+ الانتقال مباشرة إلى شاشة التقديم دون المرور على تفاصيل أخرى.
+ فتح النموذج
+
+
+ مراجعة شاملة
+ فتح لوحة الطلبات مع جميع السجلات وحالاتها الحالية.
+ فتح القائمة
+
+
+ هيكل النظام
+ مراجعة النطاق الحالي والصفحات المفصولة ضمن النسخة الأولية.
+ فتح الصفحة
+
+
+
+
+
+
+
+
diff --git a/db/migrations/20260416_center_applications.sql b/db/migrations/20260416_center_applications.sql
new file mode 100644
index 0000000..2dea565
--- /dev/null
+++ b/db/migrations/20260416_center_applications.sql
@@ -0,0 +1,21 @@
+CREATE TABLE IF NOT EXISTS center_applications (
+ id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+ center_name VARCHAR(190) NOT NULL,
+ city VARCHAR(120) NOT NULL,
+ center_type VARCHAR(60) NOT NULL,
+ gender_scope VARCHAR(30) NOT NULL,
+ director_name VARCHAR(150) NOT NULL,
+ phone VARCHAR(60) NOT NULL,
+ email VARCHAR(190) NOT NULL,
+ expected_students INT UNSIGNED NOT NULL,
+ start_date DATE NOT NULL,
+ end_date DATE NOT NULL,
+ notes TEXT NULL,
+ status VARCHAR(30) NOT NULL DEFAULT 'submitted',
+ admin_notes TEXT NULL,
+ evaluation_score TINYINT UNSIGNED NULL,
+ submitted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ INDEX idx_center_applications_status (status),
+ INDEX idx_center_applications_submitted_at (submitted_at)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
diff --git a/healthz.php b/healthz.php
new file mode 100644
index 0000000..0897555
--- /dev/null
+++ b/healthz.php
@@ -0,0 +1,22 @@
+ 'ok',
+ 'app' => project_name(),
+ 'applications' => $metrics['all'],
+ 'timestamp' => gmdate('c'),
+ ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+} catch (Throwable $exception) {
+ http_response_code(500);
+ echo json_encode([
+ 'status' => 'error',
+ 'message' => 'Database unavailable',
+ 'timestamp' => gmdate('c'),
+ ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+}
diff --git a/includes/app.php b/includes/app.php
new file mode 100644
index 0000000..a5700d3
--- /dev/null
+++ b/includes/app.php
@@ -0,0 +1,493 @@
+ $type,
+ 'message' => $message,
+ ];
+}
+
+function consume_flash(): ?array
+{
+ if (empty($_SESSION['flash']) || !is_array($_SESSION['flash'])) {
+ return null;
+ }
+
+ $flash = $_SESSION['flash'];
+ unset($_SESSION['flash']);
+
+ return $flash;
+}
+
+function status_map(): array
+{
+ return [
+ 'submitted' => ['label' => 'قيد الاستلام', 'class' => 'status-submitted'],
+ 'under_review' => ['label' => 'تحت المراجعة', 'class' => 'status-review'],
+ 'approved' => ['label' => 'معتمد', 'class' => 'status-approved'],
+ 'rejected' => ['label' => 'بحاجة إلى استكمال', 'class' => 'status-rejected'],
+ ];
+}
+
+function status_meta(string $status): array
+{
+ $map = status_map();
+ return $map[$status] ?? ['label' => 'غير معروف', 'class' => 'status-muted'];
+}
+
+function status_badge(string $status): string
+{
+ $meta = status_meta($status);
+ return '' . e($meta['label']) . ' ';
+}
+
+function db_connection(): PDO
+{
+ static $pdo = null;
+ static $bootstrapped = false;
+
+ if (!$pdo instanceof PDO) {
+ $pdo = db();
+ }
+
+ if (!$bootstrapped) {
+ ensure_center_application_schema($pdo);
+ seed_center_application_demo_data($pdo);
+ $bootstrapped = true;
+ }
+
+ return $pdo;
+}
+
+function ensure_center_application_schema(PDO $pdo): void
+{
+ static $done = false;
+ if ($done) {
+ return;
+ }
+
+ $migrationPath = __DIR__ . '/../db/migrations/20260416_center_applications.sql';
+ if (is_file($migrationPath)) {
+ $sql = file_get_contents($migrationPath);
+ if (is_string($sql) && trim($sql) !== '') {
+ $pdo->exec($sql);
+ }
+ }
+
+ $done = true;
+}
+
+function seed_center_application_demo_data(PDO $pdo): void
+{
+ $count = (int) $pdo->query('SELECT COUNT(*) FROM center_applications')->fetchColumn();
+ if ($count > 0) {
+ return;
+ }
+
+ $rows = [
+ [
+ 'مركز النور الصيفي', 'العاصمة', 'بنين', 'طلاب', 'أ. خالد السالمي', '0501234567', 'alnoor@example.com',
+ 180, '2026-06-15', '2026-08-15', 'يركز على القرآن والمهارات الرقمية والأنشطة الرياضية المسائية.',
+ 'submitted', 'بانتظار زيارة ميدانية أولية.', null,
+ ],
+ [
+ 'مركز الواحة للفتيات', 'الزور', 'بنات', 'طالبات', 'أ. نورة الشيبانية', '0507654321', 'alwaha@example.com',
+ 140, '2026-06-20', '2026-08-10', 'طلب تجهيز معمل حاسب وقاعة أنشطة فنية.',
+ 'under_review', 'تمت مراجعة الوثائق والمطلوب استكمال خطة الأمن والسلامة.', 82,
+ ],
+ [
+ 'مركز الريادة المجتمعي', 'الساحل', 'مختلط', 'طلاب وطالبات', 'أ. سيف الحارثي', '0509988776', 'riyadah@example.com',
+ 220, '2026-06-18', '2026-08-20', 'يشمل برنامجاً علمياً ومساراً للابتكار ومتابعة أسرية.',
+ 'approved', 'المركز مستوفٍ للاشتراطات ويُنصح ببدء التسجيل.', 94,
+ ],
+ ];
+
+ $stmt = $pdo->prepare(
+ 'INSERT INTO center_applications (
+ center_name, city, center_type, gender_scope, director_name, phone, email,
+ expected_students, start_date, end_date, notes, status, admin_notes, evaluation_score,
+ submitted_at, updated_at
+ ) VALUES (
+ :center_name, :city, :center_type, :gender_scope, :director_name, :phone, :email,
+ :expected_students, :start_date, :end_date, :notes, :status, :admin_notes, :evaluation_score,
+ NOW(), NOW()
+ )'
+ );
+
+ foreach ($rows as $row) {
+ $stmt->execute([
+ ':center_name' => $row[0],
+ ':city' => $row[1],
+ ':center_type' => $row[2],
+ ':gender_scope' => $row[3],
+ ':director_name' => $row[4],
+ ':phone' => $row[5],
+ ':email' => $row[6],
+ ':expected_students' => $row[7],
+ ':start_date' => $row[8],
+ ':end_date' => $row[9],
+ ':notes' => $row[10],
+ ':status' => $row[11],
+ ':admin_notes' => $row[12],
+ ':evaluation_score' => $row[13],
+ ]);
+ }
+}
+
+function clean_text(string $value, int $limit = 255): string
+{
+ $normalized = preg_replace('/\s+/u', ' ', trim($value));
+ if (!is_string($normalized)) {
+ $normalized = trim($value);
+ }
+
+ if (function_exists('mb_substr')) {
+ return mb_substr($normalized, 0, $limit);
+ }
+
+ return substr($normalized, 0, $limit);
+}
+
+function application_defaults(): array
+{
+ return [
+ 'center_name' => '',
+ 'city' => '',
+ 'center_type' => '',
+ 'gender_scope' => '',
+ 'director_name' => '',
+ 'phone' => '',
+ 'email' => '',
+ 'expected_students' => '',
+ 'start_date' => '',
+ 'end_date' => '',
+ 'notes' => '',
+ ];
+}
+
+function validate_application_input(array $input): array
+{
+ $data = application_defaults();
+ foreach ($data as $key => $_value) {
+ $data[$key] = clean_text((string) ($input[$key] ?? ''), $key === 'notes' ? 1000 : 190);
+ }
+
+ $errors = [];
+
+ if ($data['center_name'] === '') {
+ $errors['center_name'] = 'يرجى إدخال اسم المركز.';
+ }
+ if ($data['city'] === '') {
+ $errors['city'] = 'يرجى اختيار المدينة أو الولاية الفرعية.';
+ }
+ if ($data['center_type'] === '') {
+ $errors['center_type'] = 'يرجى تحديد نوع المركز.';
+ }
+ if ($data['gender_scope'] === '') {
+ $errors['gender_scope'] = 'يرجى تحديد الفئة المستهدفة.';
+ }
+ if ($data['director_name'] === '') {
+ $errors['director_name'] = 'يرجى إدخال اسم مدير أو مديرة المركز.';
+ }
+ if ($data['phone'] === '') {
+ $errors['phone'] = 'يرجى إدخال رقم الهاتف.';
+ }
+ if ($data['email'] === '' || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
+ $errors['email'] = 'يرجى إدخال بريد إلكتروني صحيح.';
+ }
+
+ $expectedStudents = filter_var($input['expected_students'] ?? null, FILTER_VALIDATE_INT, [
+ 'options' => ['min_range' => 10, 'max_range' => 2000],
+ ]);
+ if ($expectedStudents === false) {
+ $errors['expected_students'] = 'أدخل عدداً صحيحاً بين 10 و2000.';
+ } else {
+ $data['expected_students'] = (string) $expectedStudents;
+ }
+
+ $startDate = clean_text((string) ($input['start_date'] ?? ''), 20);
+ $endDate = clean_text((string) ($input['end_date'] ?? ''), 20);
+ $data['start_date'] = $startDate;
+ $data['end_date'] = $endDate;
+
+ if ($startDate === '') {
+ $errors['start_date'] = 'حدد تاريخ بداية البرنامج.';
+ }
+ if ($endDate === '') {
+ $errors['end_date'] = 'حدد تاريخ نهاية البرنامج.';
+ }
+ if ($startDate !== '' && $endDate !== '' && strtotime($endDate) < strtotime($startDate)) {
+ $errors['end_date'] = 'يجب أن يكون تاريخ النهاية بعد البداية.';
+ }
+
+ return [$data, $errors];
+}
+
+function create_application(array $data): int
+{
+ $pdo = db_connection();
+ $stmt = $pdo->prepare(
+ 'INSERT INTO center_applications (
+ center_name, city, center_type, gender_scope, director_name, phone, email,
+ expected_students, start_date, end_date, notes, status, submitted_at, updated_at
+ ) VALUES (
+ :center_name, :city, :center_type, :gender_scope, :director_name, :phone, :email,
+ :expected_students, :start_date, :end_date, :notes, :status, NOW(), NOW()
+ )'
+ );
+
+ $stmt->execute([
+ ':center_name' => $data['center_name'],
+ ':city' => $data['city'],
+ ':center_type' => $data['center_type'],
+ ':gender_scope' => $data['gender_scope'],
+ ':director_name' => $data['director_name'],
+ ':phone' => $data['phone'],
+ ':email' => $data['email'],
+ ':expected_students' => (int) $data['expected_students'],
+ ':start_date' => $data['start_date'],
+ ':end_date' => $data['end_date'],
+ ':notes' => $data['notes'],
+ ':status' => 'submitted',
+ ]);
+
+ return (int) $pdo->lastInsertId();
+}
+
+function list_applications(string $status = 'all'): array
+{
+ $pdo = db_connection();
+ if ($status === 'all' || !array_key_exists($status, status_map())) {
+ $stmt = $pdo->query('SELECT * FROM center_applications ORDER BY submitted_at DESC, id DESC');
+ return $stmt->fetchAll();
+ }
+
+ $stmt = $pdo->prepare('SELECT * FROM center_applications WHERE status = :status ORDER BY submitted_at DESC, id DESC');
+ $stmt->execute([':status' => $status]);
+ return $stmt->fetchAll();
+}
+
+function get_application(int $id): ?array
+{
+ $pdo = db_connection();
+ $stmt = $pdo->prepare('SELECT * FROM center_applications WHERE id = :id LIMIT 1');
+ $stmt->execute([':id' => $id]);
+ $row = $stmt->fetch();
+ return $row ?: null;
+}
+
+function update_application_review(int $id, string $status, string $adminNotes, ?int $evaluationScore): void
+{
+ $allowed = array_keys(status_map());
+ if (!in_array($status, $allowed, true)) {
+ throw new InvalidArgumentException('Invalid status value.');
+ }
+
+ $pdo = db_connection();
+ $stmt = $pdo->prepare(
+ 'UPDATE center_applications
+ SET status = :status, admin_notes = :admin_notes, evaluation_score = :evaluation_score, updated_at = NOW()
+ WHERE id = :id'
+ );
+ $stmt->bindValue(':status', $status, PDO::PARAM_STR);
+ $stmt->bindValue(':admin_notes', $adminNotes !== '' ? $adminNotes : null, $adminNotes !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL);
+ $stmt->bindValue(':evaluation_score', $evaluationScore, $evaluationScore !== null ? PDO::PARAM_INT : PDO::PARAM_NULL);
+ $stmt->bindValue(':id', $id, PDO::PARAM_INT);
+ $stmt->execute();
+}
+
+function dashboard_metrics(): array
+{
+ $pdo = db_connection();
+ $totals = [
+ 'all' => 0,
+ 'submitted' => 0,
+ 'under_review' => 0,
+ 'approved' => 0,
+ 'rejected' => 0,
+ 'expected_students' => 0,
+ ];
+
+ $summary = $pdo->query('SELECT status, COUNT(*) AS total FROM center_applications GROUP BY status')->fetchAll();
+ foreach ($summary as $row) {
+ $status = (string) ($row['status'] ?? '');
+ $count = (int) ($row['total'] ?? 0);
+ if (array_key_exists($status, $totals)) {
+ $totals[$status] = $count;
+ $totals['all'] += $count;
+ }
+ }
+
+ $totals['expected_students'] = (int) $pdo->query('SELECT COALESCE(SUM(expected_students), 0) FROM center_applications')->fetchColumn();
+
+ return $totals;
+}
+
+function latest_applications(int $limit = 5): array
+{
+ $pdo = db_connection();
+ $stmt = $pdo->prepare('SELECT * FROM center_applications ORDER BY submitted_at DESC, id DESC LIMIT :limit');
+ $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
+ $stmt->execute();
+ return $stmt->fetchAll();
+}
+
+function render_page_start(string $pageTitle, string $active = 'home', string $pageDescription = ''): void
+{
+ $projectName = project_name();
+ $description = $pageDescription !== '' ? $pageDescription : project_description();
+ $projectImageUrl = env_value('PROJECT_IMAGE_URL');
+ ?>
+
+
+
+
+
+ = e($pageTitle) ?> | = e($projectName) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'text-bg-success',
+ 'error' => 'text-bg-danger',
+ default => 'text-bg-dark',
+ };
+ ?>
+
+
+
+
= e((string) $flash['message']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Analyzing your requirements and generating your website…
-
-
Loading…
+
+
+
+
+
+
واجهة رئيسية منظمة للمشرف العام
+
كل مهمة في صفحة مستقلة وواضحة.
+
تم تنظيم النسخة الحالية بحيث تكون الصفحة الرئيسية نقطة دخول فقط، بينما توجد صفحة منفصلة للمتابعة التشغيلية، وصفحة مستقلة للطلبات، وصفحة خاصة ببنية النظام والنطاق الحالي.
+
+
+ تنظيم أفضل للشاشات
+ واجهة عربية RTL
+ جاهزة للتوسع إلى التسجيل والحضور
+
+
+
+
+
+
+
+
إجمالي الطلبات
+
= e($stats['all']) ?>
+
إجمالي الطلبات المسجلة
+
+
+
+
+
المعتمد
+
= e($stats['approved']) ?>
+
مراكز جاهزة للتشغيل
+
+
+
+
+
تحت المراجعة
+
= e($stats['under_review']) ?>
+
طلبات تحتاج متابعة
+
+
+
+
+
الطاقة المقترحة
+
= e($stats['expected_students']) ?>
+
عدد الطلاب المتوقع
+
+
+
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
-
-
- Page updated: = htmlspecialchars($now) ?> (UTC)
-
-
-
+
+
+
+
+
+
+
+
الوصول السريع حسب المهمة
+
بدلاً من خلط كل شيء في صفحة واحدة، كل جزء أصبح له شاشة مستقلة ليسهل على المستخدم الوصول والتنقل.
+
+
+
+
+
+ لوحة القيادة
+ مؤشرات سريعة وآخر الطلبات الواردة للمشرف العام.
+ فتح الصفحة
+
+
+
+
+ طلب فتح مركز
+ نموذج التقديم الكامل في شاشة منفصلة بدون تشتيت.
+ فتح الصفحة
+
+
+
+
+ لوحة الطلبات
+ جدول موحد مع التصفية بالحالة والانتقال للتفاصيل.
+ فتح الصفحة
+
+
+
+
+ هيكل النظام
+ صفحة مخصصة للنطاق الحالي ومسار التوسع القادم.
+ فتح الصفحة
+
+
+
+
+
+
diff --git a/modules.php b/modules.php
new file mode 100644
index 0000000..cfb2f78
--- /dev/null
+++ b/modules.php
@@ -0,0 +1,69 @@
+
+
+
+
+
هيكل الصفحات والوحدات
+
تم فصل المحتوى التعريفي والتنظيمي في هذه الصفحة حتى تبقى الصفحات التشغيلية مركزة: التقديم في شاشة، المتابعة في شاشة، والتفاصيل في شاشة مستقلة.
+
+
+
+
+
+
النطاق الحالي في هذه النسخة
+
+
+ 1. الرئيسية
+ صفحة دخول مرتبة مع بطاقات وصول سريع إلى كل جزء من النظام دون خلط التفاصيل التشغيلية.
+
+
+ 2. لوحة القيادة
+ شاشة متابعة يومية تعرض المؤشرات وآخر الطلبات الواردة للمشرف العام.
+
+
+ 3. طلب فتح مركز
+ نموذج عربي كامل مع تحقق للحقول الأساسية والطاقة التشغيلية ومواعيد البرنامج.
+
+
+ 4. لوحة الطلبات
+ قائمة موحدة مع فرز بالحالة لتسهيل العمل الإشرافي والانتقال السريع للتفاصيل.
+
+
+ 5. صفحة المراجعة التفصيلية
+ عرض بيانات المركز، تسجيل الملاحظات، تحديث الحالة، وإسناد التقييم الأولي.
+
+
+
+
+
+
+
مسار الاستخدام الحالي
+
+ يرسل مدير المركز طلب الافتتاح من شاشة مستقلة.
+ تظهر الطلبات فوراً داخل لوحة الطلبات ولوحة القيادة.
+ يفتح المشرف العام صفحة التفاصيل لإضافة الملاحظات والتقييم.
+ تُحدث الحالة إلى قيد الاستلام أو تحت المراجعة أو معتمد أو بحاجة إلى استكمال.
+
+
+
ما الذي تم تحسينه؟
+
أصبح التنظيم أوضح لأن كل صفحة الآن تؤدي غرضاً واحداً محدداً، وهذا أسهل للتوسع لاحقاً إلى التسجيل الطلابي، الحضور، والتقييمات التشغيلية.
+
+
المرحلة التالية المقترحة
+
بعد هذا التنظيم، الخطوة الطبيعية التالية هي بناء وحدات الطلاب والتسجيل في المراكز المعتمدة مع نفس المبدأ: صفحة مستقلة لكل وظيفة.
+
+
+
+
+
+
+