$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 ''; } function db_connection(): PDO { static $pdo = null; static $bootstrapped = false; if (!$pdo instanceof PDO) { $pdo = db(); } if (!$bootstrapped) { ensure_center_application_schema($pdo); ensure_school_module_schema($pdo); seed_center_application_demo_data($pdo); seed_school_module_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 ensure_school_module_schema(PDO $pdo): void { static $done = false; if ($done) { return; } $migrationPath = __DIR__ . '/../db/migrations/20260416_school_modules.sql'; if (is_file($migrationPath)) { $sql = file_get_contents($migrationPath); if (is_string($sql) && trim($sql) !== '') { $pdo->exec($sql); } } $done = true; } function seed_school_module_demo_data(PDO $pdo): void { $approvedId = (int) $pdo->query("SELECT id FROM center_applications WHERE status = 'approved' ORDER BY id ASC LIMIT 1")->fetchColumn(); if ($approvedId <= 0) { return; } $studentCount = (int) $pdo->query('SELECT COUNT(*) FROM school_students')->fetchColumn(); if ($studentCount === 0) { $studentRows = [ ['ST-301', 'أحمد بن سالم الحارثي', 'طالب', 'الصف السابع', 'سالم الحارثي', '0501112233', '2013-03-11', 'active', 'مسجل في مسار القرآن والابتكار.'], ['ST-302', 'مريم بنت ناصر الكندية', 'طالبة', 'الصف الثامن', 'ناصر الكندي', '0502223344', '2012-11-05', 'active', 'بحاجة إلى متابعة في الأنشطة العلمية.'], ['ST-303', 'سيف بن راشد المقبالي', 'طالب', 'الصف السادس', 'راشد المقبالي', '0503334455', '2014-01-22', 'waiting', 'بانتظار تأكيد المقعد بعد مراجعة السعة.'], ]; $studentStmt = $pdo->prepare( 'INSERT INTO school_students ( center_application_id, student_code, full_name, gender, grade_level, guardian_name, guardian_phone, birth_date, enrollment_status, notes, created_at, updated_at ) VALUES ( :center_application_id, :student_code, :full_name, :gender, :grade_level, :guardian_name, :guardian_phone, :birth_date, :enrollment_status, :notes, NOW(), NOW() )' ); foreach ($studentRows as $row) { $studentStmt->execute([ ':center_application_id' => $approvedId, ':student_code' => $row[0], ':full_name' => $row[1], ':gender' => $row[2], ':grade_level' => $row[3], ':guardian_name' => $row[4], ':guardian_phone' => $row[5], ':birth_date' => $row[6], ':enrollment_status' => $row[7], ':notes' => $row[8], ]); } } $teacherCount = (int) $pdo->query('SELECT COUNT(*) FROM school_teachers')->fetchColumn(); if ($teacherCount === 0) { $teacherRows = [ ['أ. هدى بنت راشد المعمرية', 'مشرفة أكاديمية', 'اللغة العربية والقرآن', '0504445566', 'huda.muamari@example.com', 'active', 'تقود خطة الإشراف الأكاديمي لهذا الموسم.'], ['أ. مازن بن سعيد البلوشي', 'منسق أنشطة', 'الأنشطة العلمية والابتكار', '0505556677', 'mazin.balushi@example.com', 'active', 'مسؤول عن الربط بين الأنشطة الصفية والفعاليات الأسبوعية.'], ['أ. عائشة بنت خالد السعدية', 'معلمة', 'الرياضيات والمهارات الرقمية', '0506667788', 'aisha.saadiya@example.com', 'pending', 'بانتظار استكمال جدولها النهائي قبل التفعيل الكامل.'], ]; $teacherStmt = $pdo->prepare( 'INSERT INTO school_teachers ( center_application_id, full_name, role_title, specialization, phone, email, employment_status, notes, created_at, updated_at ) VALUES ( :center_application_id, :full_name, :role_title, :specialization, :phone, :email, :employment_status, :notes, NOW(), NOW() )' ); foreach ($teacherRows as $row) { $teacherStmt->execute([ ':center_application_id' => $approvedId, ':full_name' => $row[0], ':role_title' => $row[1], ':specialization' => $row[2], ':phone' => $row[3], ':email' => $row[4], ':employment_status' => $row[5], ':notes' => $row[6], ]); } } } 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 student_defaults(): array { return [ 'student_code' => '', 'full_name' => '', 'gender' => '', 'grade_level' => '', 'guardian_name' => '', 'guardian_phone' => '', 'birth_date' => '', 'enrollment_status' => 'active', 'notes' => '', ]; } function student_gender_options(): array { return ['طالب', 'طالبة']; } function student_grade_options(): array { return [ 'الصف الرابع', 'الصف الخامس', 'الصف السادس', 'الصف السابع', 'الصف الثامن', 'الصف التاسع', 'الصف العاشر', 'الصف الحادي عشر', 'الصف الثاني عشر', ]; } function student_enrollment_status_map(): array { return [ 'active' => ['label' => 'مسجل', 'class' => 'status-approved'], 'waiting' => ['label' => 'قائمة انتظار', 'class' => 'status-review'], 'withdrawn' => ['label' => 'منسحب', 'class' => 'status-muted'], ]; } function student_enrollment_status_badge(string $status): string { $map = student_enrollment_status_map(); $meta = $map[$status] ?? ['label' => 'غير محدد', 'class' => 'status-muted']; return ''; } function validate_student_input(array $input): array { $data = student_defaults(); foreach ($data as $key => $_value) { $limit = $key === 'notes' ? 1000 : ($key === 'student_code' ? 60 : 190); $data[$key] = clean_text((string) ($input[$key] ?? ''), $limit); } $errors = []; if ($data['student_code'] === '') { $errors['student_code'] = 'يرجى إدخال الرقم أو الكود المرجعي للطالب.'; } if ($data['full_name'] === '') { $errors['full_name'] = 'يرجى إدخال اسم الطالب أو الطالبة.'; } if (!in_array($data['gender'], student_gender_options(), true)) { $errors['gender'] = 'يرجى تحديد النوع.'; } if (!in_array($data['grade_level'], student_grade_options(), true)) { $errors['grade_level'] = 'يرجى اختيار الصف الدراسي.'; } if ($data['guardian_name'] === '') { $errors['guardian_name'] = 'يرجى إدخال اسم ولي الأمر.'; } if ($data['guardian_phone'] === '' || strlen($data['guardian_phone']) < 7) { $errors['guardian_phone'] = 'يرجى إدخال رقم هاتف صحيح لولي الأمر.'; } $birthDate = clean_text((string) ($input['birth_date'] ?? ''), 20); $data['birth_date'] = $birthDate; if ($birthDate !== '' && strtotime($birthDate) === false) { $errors['birth_date'] = 'يرجى إدخال تاريخ ميلاد صحيح أو تركه فارغاً.'; } $statusMap = student_enrollment_status_map(); if (!array_key_exists($data['enrollment_status'], $statusMap)) { $errors['enrollment_status'] = 'يرجى اختيار حالة تسجيل صحيحة.'; } return [$data, $errors]; } function create_student(int $centerApplicationId, array $data): int { $pdo = db_connection(); $stmt = $pdo->prepare( 'INSERT INTO school_students ( center_application_id, student_code, full_name, gender, grade_level, guardian_name, guardian_phone, birth_date, enrollment_status, notes, created_at, updated_at ) VALUES ( :center_application_id, :student_code, :full_name, :gender, :grade_level, :guardian_name, :guardian_phone, :birth_date, :enrollment_status, :notes, NOW(), NOW() )' ); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->bindValue(':student_code', $data['student_code'], PDO::PARAM_STR); $stmt->bindValue(':full_name', $data['full_name'], PDO::PARAM_STR); $stmt->bindValue(':gender', $data['gender'], PDO::PARAM_STR); $stmt->bindValue(':grade_level', $data['grade_level'], PDO::PARAM_STR); $stmt->bindValue(':guardian_name', $data['guardian_name'], PDO::PARAM_STR); $stmt->bindValue(':guardian_phone', $data['guardian_phone'], PDO::PARAM_STR); $stmt->bindValue(':birth_date', $data['birth_date'] !== '' ? $data['birth_date'] : null, $data['birth_date'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->bindValue(':enrollment_status', $data['enrollment_status'], PDO::PARAM_STR); $stmt->bindValue(':notes', $data['notes'] !== '' ? $data['notes'] : null, $data['notes'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->execute(); return (int) $pdo->lastInsertId(); } function list_school_students(int $centerApplicationId): array { $pdo = db_connection(); $stmt = $pdo->prepare('SELECT * FROM school_students WHERE center_application_id = :center_application_id ORDER BY created_at DESC, id DESC'); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); } function school_student_metrics(int $centerApplicationId): array { $pdo = db_connection(); $stmt = $pdo->prepare( "SELECT COUNT(*) AS total, COALESCE(SUM(gender = 'طالب'), 0) AS boys, COALESCE(SUM(gender = 'طالبة'), 0) AS girls, COALESCE(SUM(enrollment_status = 'active'), 0) AS active_count, COALESCE(SUM(enrollment_status = 'waiting'), 0) AS waiting_count, COALESCE(SUM(enrollment_status = 'withdrawn'), 0) AS withdrawn_count FROM school_students WHERE center_application_id = :center_application_id" ); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->execute(); $row = $stmt->fetch() ?: []; return [ 'total' => (int) ($row['total'] ?? 0), 'boys' => (int) ($row['boys'] ?? 0), 'girls' => (int) ($row['girls'] ?? 0), 'active' => (int) ($row['active_count'] ?? 0), 'waiting' => (int) ($row['waiting_count'] ?? 0), 'withdrawn' => (int) ($row['withdrawn_count'] ?? 0), ]; } function teacher_defaults(): array { return [ 'full_name' => '', 'role_title' => '', 'specialization' => '', 'phone' => '', 'email' => '', 'employment_status' => 'active', 'notes' => '', ]; } function teacher_role_options(): array { return [ 'معلم', 'معلمة', 'مشرف أكاديمي', 'مشرفة أكاديمية', 'منسق أنشطة', 'مسؤول متابعة', 'إداري', ]; } function teacher_employment_status_map(): array { return [ 'active' => ['label' => 'مفعل', 'class' => 'status-approved'], 'pending' => ['label' => 'بانتظار التفعيل', 'class' => 'status-review'], 'inactive' => ['label' => 'غير مفعل', 'class' => 'status-muted'], ]; } function teacher_employment_status_badge(string $status): string { $map = teacher_employment_status_map(); $meta = $map[$status] ?? ['label' => 'غير محدد', 'class' => 'status-muted']; return ''; } function validate_teacher_input(array $input): array { $data = teacher_defaults(); foreach ($data as $key => $_value) { $limit = $key === 'notes' ? 1000 : 190; $data[$key] = clean_text((string) ($input[$key] ?? ''), $limit); } $errors = []; if ($data['full_name'] === '') { $errors['full_name'] = 'يرجى إدخال اسم عضو الفريق.'; } if (!in_array($data['role_title'], teacher_role_options(), true)) { $errors['role_title'] = 'يرجى اختيار الدور الوظيفي.'; } if ($data['phone'] !== '' && strlen($data['phone']) < 7) { $errors['phone'] = 'أدخل رقم هاتف صحيحاً أو اتركه فارغاً.'; } if ($data['email'] !== '' && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) { $errors['email'] = 'أدخل بريداً إلكترونياً صحيحاً أو اتركه فارغاً.'; } $statusMap = teacher_employment_status_map(); if (!array_key_exists($data['employment_status'], $statusMap)) { $errors['employment_status'] = 'يرجى اختيار حالة توظيف صحيحة.'; } return [$data, $errors]; } function create_teacher(int $centerApplicationId, array $data): int { $pdo = db_connection(); $stmt = $pdo->prepare( 'INSERT INTO school_teachers ( center_application_id, full_name, role_title, specialization, phone, email, employment_status, notes, created_at, updated_at ) VALUES ( :center_application_id, :full_name, :role_title, :specialization, :phone, :email, :employment_status, :notes, NOW(), NOW() )' ); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->bindValue(':full_name', $data['full_name'], PDO::PARAM_STR); $stmt->bindValue(':role_title', $data['role_title'], PDO::PARAM_STR); $stmt->bindValue(':specialization', $data['specialization'] !== '' ? $data['specialization'] : null, $data['specialization'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->bindValue(':phone', $data['phone'] !== '' ? $data['phone'] : null, $data['phone'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->bindValue(':email', $data['email'] !== '' ? $data['email'] : null, $data['email'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->bindValue(':employment_status', $data['employment_status'], PDO::PARAM_STR); $stmt->bindValue(':notes', $data['notes'] !== '' ? $data['notes'] : null, $data['notes'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); $stmt->execute(); return (int) $pdo->lastInsertId(); } function list_school_teachers(int $centerApplicationId): array { $pdo = db_connection(); $stmt = $pdo->prepare('SELECT * FROM school_teachers WHERE center_application_id = :center_application_id ORDER BY created_at DESC, id DESC'); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); } function school_teacher_metrics(int $centerApplicationId): array { $pdo = db_connection(); $stmt = $pdo->prepare( "SELECT COUNT(*) AS total, COALESCE(SUM(employment_status = 'active'), 0) AS active_count, COALESCE(SUM(employment_status = 'pending'), 0) AS pending_count, COALESCE(SUM(employment_status = 'inactive'), 0) AS inactive_count, COALESCE(SUM(email IS NOT NULL AND email <> ''), 0) AS email_ready_count, COALESCE(SUM(role_title LIKE '%مشرف%'), 0) AS supervisors_count FROM school_teachers WHERE center_application_id = :center_application_id" ); $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); $stmt->execute(); $row = $stmt->fetch() ?: []; return [ 'total' => (int) ($row['total'] ?? 0), 'active' => (int) ($row['active_count'] ?? 0), 'pending' => (int) ($row['pending_count'] ?? 0), 'inactive' => (int) ($row['inactive_count'] ?? 0), 'email_ready' => (int) ($row['email_ready_count'] ?? 0), 'supervisors' => (int) ($row['supervisors_count'] ?? 0), ]; } 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'); ?>