success([ 'event_types' => $this->contextService->eventTypes(), 'defaults' => [ 'school_year' => $this->contextService->defaultSchoolYear(), 'semester' => $this->contextService->defaultSemester(), ], ]); } public function index(SchoolCalendarIndexRequest $request): JsonResponse { $filters = $request->validated(); $audience = $filters['audience'] ?? null; $includeMeetings = array_key_exists('include_meetings', $filters) ? (bool) $filters['include_meetings'] : true; if (empty($filters['school_year'])) { $filters['school_year'] = $this->contextService->defaultSchoolYear(); } $events = $this->queryService->listEvents($filters); $events = $this->queryService->filterEventsForAudience($events, $audience); $formatted = $events->map(function ($event) use ($audience) { return $this->formatterService->formatEvent($event, $audience); })->all(); if ($includeMeetings) { $parentUserId = $audience === 'parent' ? (int) (auth()->id() ?? 0) : null; $meetingRows = $this->meetingService->listMeetings($filters['school_year'] ?? '', $audience, $parentUserId); foreach ($meetingRows as $row) { $formatted[] = $this->formatterService->formatMeetingEvent($row, $audience); } } return $this->success([ 'events' => SchoolCalendarEventResource::collection($formatted), ]); } public function show(int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } return $this->success([ 'event' => new SchoolCalendarEventDetailResource($event), ]); } public function store(SchoolCalendarStoreRequest $request): JsonResponse { $payload = $request->validated(); $targets = $this->extractEmailTargets($payload); try { $result = $this->mutationService->create($payload, $targets); } catch (\Throwable $e) { Log::error('SchoolCalendar store failed: ' . $e->getMessage()); return $this->error('Failed to save event.', Response::HTTP_INTERNAL_SERVER_ERROR); } return $this->success([ 'event' => new SchoolCalendarEventDetailResource($result['event']), 'email_status' => $result['email_status'] ?? [], ], 'Event added successfully.', Response::HTTP_CREATED); } public function update(SchoolCalendarUpdateRequest $request, int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } $payload = $request->validated(); $targets = $this->extractEmailTargets($payload); try { $result = $this->mutationService->update($event, $payload, $targets); } catch (\Throwable $e) { Log::error('SchoolCalendar update failed: ' . $e->getMessage()); return $this->error('Failed to update event.', Response::HTTP_INTERNAL_SERVER_ERROR); } return $this->success([ 'event' => new SchoolCalendarEventDetailResource($result['event']), 'email_status' => $result['email_status'] ?? [], ], 'Event updated successfully.'); } public function destroy(int $eventId): JsonResponse { $event = $this->queryService->findEvent($eventId); if (!$event) { return $this->error('Event not found.', Response::HTTP_NOT_FOUND); } try { $this->mutationService->delete($event); } catch (\Throwable $e) { Log::error('SchoolCalendar delete failed: ' . $e->getMessage()); return $this->error('Failed to delete event.', Response::HTTP_INTERNAL_SERVER_ERROR); } return $this->success(null, 'Event deleted successfully.'); } private function extractEmailTargets(array $payload): array { return [ 'parents' => !empty($payload['send_email_parent']), 'teachers' => !empty($payload['send_email_teacher']), 'admins' => !empty($payload['send_email_admin']), ]; } }