parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $data = $this->attendanceService->listAttendance($guard, $request->validated()['school_year'] ?? null); return response()->json([ 'ok' => true, 'attendance' => ParentAttendanceResource::collection($data['attendance']), 'schoolYears' => $data['schoolYears'], 'selectedYear' => $data['selectedYear'], ]); } public function invoices(ParentInvoiceRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $schoolYear = $request->validated()['school_year'] ?? null; $rows = $this->invoiceService->listInvoices($guard, $schoolYear); return response()->json([ 'ok' => true, 'invoices' => InvoiceResource::collection($rows), ]); } public function enrollments(ParentEnrollmentRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $data = $this->enrollmentService->overview($guard, $request->validated()['school_year'] ?? null); return response()->json([ 'ok' => true, 'students' => ParentStudentResource::collection($data['students']), 'schoolYears' => $data['schoolYears'], 'selectedYear' => $data['selectedYear'], 'withdrawalDeadline' => $data['withdrawalDeadline'], 'lastDayOfRegistration' => $data['lastDayOfRegistration'], 'schoolStartDate' => $data['schoolStartDate'], ]); } public function progress(Request $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $schoolYear = $this->schoolYears->currentSchoolYear($request->query('school_year')); $semester = $request->query->has('semester') ? $this->schoolYears->currentSemester($request->query('semester')) : null; $sectionIds = $this->progressService->parentSectionIds($guard); $reports = $this->progressService->reportsForSections($sectionIds, $schoolYear, $semester); $groups = array_values($this->progressService->groupReportsByWeek($reports)); return response()->json([ 'ok' => true, 'data' => [ 'items' => $groups, 'groups' => $groups, 'students' => $this->progressService->parentStudents($guard), 'meta' => $this->schoolYears->options($schoolYear, $semester), ], ]); } public function progressDetail(Request $request, ClassProgressReport $class_progress): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } if (Gate::denies('view', $class_progress)) { return response()->json(['ok' => false, 'status' => false, 'message' => 'Forbidden.'], 403); } $weekStart = $class_progress->week_start?->format('Y-m-d') ?? ''; $weeklyReports = $this->progressService->weeklyReportsForSectionWeek( (int) $class_progress->class_section_id, $weekStart ); $data = (new ClassProgressShowResource([ 'report' => $class_progress, 'weekly_reports' => $weeklyReports, 'status_options' => config('progress.status_options', []), ]))->toArray($request); return response()->json([ 'ok' => true, 'status' => true, 'data' => $data, ]); } public function updateEnrollments(ParentEnrollmentActionRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $payload = $request->validated(); $result = $this->enrollmentService->updateEnrollment( $guard, $payload['enroll'] ?? [], $payload['withdraw'] ?? [] ); return response()->json([ 'ok' => true, 'enrolled' => $result['enrolled'], 'withdrawn' => $result['withdrawn'], 'data' => [ 'enrolled' => $result['enrolled'], 'withdrawn' => $result['withdrawn'], ], ]); } public function registration(): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $data = $this->registrationService->overview($guard); return response()->json([ 'ok' => true, 'parent' => $data['parent'], 'existingKids' => ParentStudentResource::collection($data['existingKids']), 'emergencies' => ParentEmergencyContactResource::collection($data['emergencies']), 'maxChilds' => $data['maxChilds'], 'maxEmergency' => $data['maxEmergency'], 'lastDayOfRegistration' => $data['lastDayOfRegistration'], 'registrationAgeDeadline' => $data['registrationAgeDeadline'], ]); } public function storeRegistration(ParentRegistrationRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $payload = $request->validated(); try { $result = $this->registrationService->register( $guard, $payload['students'] ?? [], $payload['emergency_contacts'] ?? [] ); } catch (\RuntimeException $e) { return response()->json(['ok' => false, 'message' => $e->getMessage()], 422); } $createdCount = count($result['created_student_ids']); $skipped = $result['skipped'] ?? []; return response()->json([ 'ok' => true, 'created_student_ids' => $result['created_student_ids'], 'skipped' => $skipped, ], $createdCount > 0 ? 201 : 200); } public function updateStudent(ParentStudentUpdateRequest $request, int $studentId): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $this->registrationService->updateStudent($guard, $studentId, $request->validated()); return response()->json(['ok' => true]); } public function deleteStudent(int $studentId): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } try { $this->registrationService->deleteStudent($guard, $studentId); } catch (\RuntimeException $e) { return response()->json(['ok' => false, 'message' => $e->getMessage()], 422); } return response()->json(['ok' => true]); } public function emergencyContacts(): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $rows = $this->emergencyContactService->list($guard); return response()->json([ 'ok' => true, 'contacts' => ParentEmergencyContactResource::collection($rows), ]); } public function storeEmergencyContact(ParentEmergencyContactRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $contact = $this->emergencyContactService->store($guard, $request->validated()); return response()->json([ 'ok' => true, 'contact' => new ParentEmergencyContactResource($contact), ], 201); } public function updateEmergencyContact(ParentEmergencyContactRequest $request, int $contactId): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $contact = $this->emergencyContactService->update($guard, $contactId, $request->validated()); return response()->json([ 'ok' => true, 'contact' => new ParentEmergencyContactResource($contact), ]); } public function profile(): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $profile = $this->profileService->getProfile($guard); return response()->json([ 'ok' => true, 'profile' => $profile, ]); } public function updateProfile(ParentProfileUpdateRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $profile = $this->profileService->updateProfile($guard, $request->validated()); return response()->json([ 'ok' => true, 'profile' => $profile, ]); } public function events(): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $data = $this->eventService->overview($guard); return response()->json([ 'ok' => true, 'activeEvents' => $data['activeEvents'], 'charges' => $data['charges'], 'yourStudents' => $data['yourStudents'], ]); } public function updateParticipation(ParentEventParticipationRequest $request): JsonResponse { $guard = $this->parentIdOrUnauthorized(); if ($guard instanceof JsonResponse) { return $guard; } $this->eventService->updateParticipation($guard, $request->validated()['participation'] ?? []); return response()->json(['ok' => true]); } /** * @return int|JsonResponse Effective primary-parent user id, or 401 JSON for this controller's legacy `{ ok }` shape. * * `parent.access` middleware resolves second parents (user_type=secondary) * and authorized users (user_type=tertiary) to their primary parent and * stashes the result as `primary_parent_id` on the request. If we are * called outside that middleware we fall back to the authenticated id. */ private function parentIdOrUnauthorized(): int|JsonResponse { $request = request(); $primary = (int) ($request?->attributes?->get('primary_parent_id') ?? 0); if ($primary > 0) { return $primary; } $parentId = (int) (auth()->id() ?? 0); if ($parentId <= 0) { return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401); } return $parentId; } }