userModel->find($userId); $displayName = $admin ? trim(($admin->firstname ?? '') . ' ' . ($admin->lastname ?? '')) : 'Administrator'; $semester = $this->shared->getSemester(); $schoolYear = $this->shared->getSchoolYear(); $existing = $this->staffAttendanceModel ->where('user_id', $userId) ->where('semester', $semester) ->where('school_year', $schoolYear) ->orderByDesc('date') ->get() ->toArray(); return [ 'admin_name' => $displayName, 'semester' => $semester, 'schoolYear' => $schoolYear, 'existing' => $existing, 'availableDates' => $this->shared->allowedAbsenceDates(), ]; } public function submit(Request $request, int $userId): array { $semester = $this->shared->getSemester(); $schoolYear = $this->shared->getSchoolYear(); if ($schoolYear === '') { return [ 'success' => false, 'message' => 'Semester or school year not configured.', 'status' => 422, ]; } $dates = (array) $request->input('dates', []); $reasonType = trim((string) $request->input('reason_type', '')); $reasonText = trim((string) $request->input('reason', '')); if ($reasonText === '') { return [ 'success' => false, 'message' => 'Reason is required.', 'status' => 422, ]; } $reasonBase = $reasonType !== '' ? strtolower($reasonType) : ''; $reason = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText; $allowedSet = array_fill_keys($this->shared->allowedAbsenceDates(), true); $roleName = method_exists($this->userModel, 'getUserRole') ? ($this->userModel->getUserRole($userId) ?: null) : null; $saved = 0; $invalid = []; $savedDates = []; $dates = array_values(array_unique(array_map('strval', $dates))); foreach ($dates as $d) { $d = trim($d); if ($d === '') { continue; } try { $parsed = \Carbon\Carbon::createFromFormat('Y-m-d', $d); if ($parsed->format('Y-m-d') !== $d || empty($allowedSet[$d])) { $invalid[] = $d; continue; } } catch (\Throwable) { $invalid[] = $d; continue; } $semesterForDate = $this->semesterRangeService->getSemesterForDate($d); if ($semesterForDate === '') { $semesterForDate = $semester; } $ok = $this->staffAttendanceModel->upsertOne( userId: $userId, roleName: $roleName, date: $d, semester: $semesterForDate, schoolYear: $schoolYear, status: StaffAttendance::STATUS_ABSENT, reason: $reason, editorId: $userId ); if ($ok) { $saved++; $savedDates[] = $d; } } if (!empty($invalid)) { return [ 'success' => false, 'message' => 'Invalid dates: ' . implode(', ', $invalid), 'status' => 422, ]; } $this->sendPrincipalNotification( userId: $userId, roleName: $roleName, semester: $semester, schoolYear: $schoolYear, reasonType: $reasonType, reasonText: $reasonText, dates: $dates, savedDates: $savedDates ); return [ 'success' => true, 'message' => $saved . ' day(s) saved as absent.', 'saved' => $saved, 'dates' => $savedDates, 'status' => 200, ]; } protected function sendPrincipalNotification( int $userId, ?string $roleName, string $semester, string $schoolYear, string $reasonType, string $reasonText, array $dates, array $savedDates ): void { try { $user = $this->userModel->find($userId); $fullName = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) ?: 'Administrator'; $userEmail = $user->email ?? ''; $role = $roleName ?: 'admin'; $dateList = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates); $subject = sprintf( 'TimeOff Request: %s (%s) — %s', $fullName, ucfirst((string) $role), $dateList ?: 'No dates' ); $submittedAt = now()->toDateTimeString(); $body = '
A staff time-off request was submitted from the administrator portal.
' . '| Name | ' . e($fullName) . ' |
| ' . e($userEmail) . ' | |
| Role | ' . e((string) $role) . ' |
| Semester | ' . e($semester) . ' |
| School Year | ' . e($schoolYear) . ' |
| Reason Type | ' . e($reasonType ?: '-') . ' |
| Reason | ' . e($reasonText) . ' |
| Dates | ' . e($dateList ?: '-') . ' |
| Submitted At | ' . e($submittedAt) . ' |
Click Send confirmation email to ' . e($fullName) . ' so the staff member is notified automatically. This link expires in 14 days.
'; $principalEmail = env('PRINCIPAL_EMAIL', 'principal@alrahmaisgl.org'); Mail::html($body, function ($message) use ($principalEmail, $subject) { $message->to($principalEmail)->subject($subject); }); } catch (\Throwable $e) { Log::error('Failed to send TimeOff email (admin): ' . $e->getMessage()); } } }