validated(); $schoolYear = $this->context->schoolYear($payload['school_year'] ?? null); $semester = array_key_exists('semester', $payload) ? (string) ($payload['semester'] ?? '') : $this->context->semester(); $payload['school_year'] = $schoolYear; $payload['semester'] = $semester; $payload['per_page'] = max((int) ($payload['per_page'] ?? 200), 200); $links = $this->linkService->paginate($payload); $collection = new WhatsappGroupLinkCollection($links); $linkRows = $collection->toArray($request); $sectionsRaw = $this->contactService->listParentContactsByClass($schoolYear, $semester); $sections = WhatsappClassSectionContactResource::collection($sectionsRaw)->resolve($request); $linksBySection = []; foreach ($linkRows as $link) { $sid = (int) ($link['class_section_id'] ?? 0); if ($sid > 0) { $linksBySection[(string) $sid] = $link; } } $parents = []; foreach ($sections as $section) { foreach (($section['parents'] ?? []) as $parent) { $primaryId = (int) ($parent['primary_id'] ?? 0); if ($primaryId > 0 && ! isset($parents['primary:'.$primaryId])) { [$lastname, $firstname] = $this->splitDisplayName((string) ($parent['primary_name'] ?? '')); $parents['primary:'.$primaryId] = [ 'id' => $primaryId, 'firstname' => $firstname, 'lastname' => $lastname, 'email' => (string) ($parent['primary_email'] ?? ''), 'source' => 'primary', ]; } $secondId = (int) ($parent['second_id'] ?? 0); if ($secondId > 0 && ! isset($parents['second:'.$secondId])) { [$lastname, $firstname] = $this->splitDisplayName((string) ($parent['second_name'] ?? '')); $parents['second:'.$secondId] = [ 'id' => $secondId, 'firstname' => $firstname, 'lastname' => $lastname, 'email' => (string) ($parent['second_email'] ?? ''), 'source' => 'parents', ]; } } } return $this->success([ 'schoolYear' => $schoolYear, 'semester' => $semester, 'links' => $linkRows, 'linksBySection' => $linksBySection, 'sections' => $sections, 'parents' => array_values($parents), 'meta' => $collection->with($request)['meta'], ]); } public function show(int $linkId): JsonResponse { $link = $this->linkService->findOrFail($linkId); return $this->success([ 'link' => new WhatsappGroupLinkResource($link), ]); } public function store(WhatsappLinkStoreRequest $request): JsonResponse { $link = $this->linkService->upsert($request->validated()); $code = $link->wasRecentlyCreated ? Response::HTTP_CREATED : Response::HTTP_OK; return $this->success([ 'link' => new WhatsappGroupLinkResource($link), ], 'WhatsApp group link saved.', $code); } public function update(WhatsappLinkUpdateRequest $request, int $linkId): JsonResponse { $link = $this->linkService->update($linkId, $request->validated()); return $this->success([ 'link' => new WhatsappGroupLinkResource($link), ], 'WhatsApp group link updated.'); } public function destroy(int $linkId): JsonResponse { $this->linkService->delete($linkId); return $this->success(null, 'WhatsApp group link deleted.'); } public function parentContacts(WhatsappParentContactsRequest $request): JsonResponse { $payload = $request->validated(); $schoolYear = $this->context->schoolYear($payload['school_year'] ?? null); $semester = array_key_exists('semester', $payload) ? (string) ($payload['semester'] ?? '') : $this->context->semester(); $contacts = $this->contactService->listParentContacts($schoolYear, $semester); return $this->success([ 'schoolYear' => $schoolYear, 'semester' => $semester, 'contacts' => WhatsappParentContactResource::collection($contacts), ]); } public function parentContactsByClass(WhatsappParentContactsByClassRequest $request): JsonResponse { $payload = $request->validated(); $schoolYear = $this->context->schoolYear($payload['school_year'] ?? null); $semester = array_key_exists('semester', $payload) ? (string) ($payload['semester'] ?? '') : $this->context->semester(); $sections = $this->contactService->listParentContactsByClass($schoolYear, $semester); return $this->success([ 'class_sections' => WhatsappClassSectionContactResource::collection($sections), ]); } public function sendInvites(WhatsappInviteSendRequest $request): JsonResponse { try { $result = $this->inviteService->send($request->validated()); } catch (\Throwable $e) { Log::error('WhatsApp invite send failed: '.$e->getMessage()); return $this->error('Invite processing failed.', Response::HTTP_INTERNAL_SERVER_ERROR); } if (! ($result['ok'] ?? false)) { return $this->error($result['message'] ?? 'Invite processing failed.', Response::HTTP_UNPROCESSABLE_ENTITY); } return $this->success([ 'triggered' => (int) ($result['triggered'] ?? 0), ], 'Invite processing started.'); } public function updateMembership(WhatsappMembershipUpdateRequest $request): JsonResponse { $userId = $this->authenticatedUserIdOrUnauthorized(); if ($userId instanceof JsonResponse) { return $userId; } try { $result = $this->membershipService->updateMembership($request->validated(), $userId); } catch (\Throwable $e) { Log::error('WhatsApp membership update failed: '.$e->getMessage()); return $this->error('Failed to save membership.', Response::HTTP_INTERNAL_SERVER_ERROR); } if (! ($result['ok'] ?? false)) { $code = str_contains((string) ($result['message'] ?? ''), 'missing') ? Response::HTTP_INTERNAL_SERVER_ERROR : Response::HTTP_UNPROCESSABLE_ENTITY; return $this->error($result['message'] ?? 'Failed to save membership.', $code); } return $this->success([ 'saved' => $result['saved'] ?? [], 'term' => $result['term'] ?? [], ], 'Membership saved.'); } private function splitDisplayName(string $name): array { $name = trim($name); if ($name === '') { return ['', '']; } if (str_contains($name, ',')) { [$last, $first] = array_pad(array_map('trim', explode(',', $name, 2)), 2, ''); return [$last, $first]; } return [$name, '']; } private function authenticatedUserIdOrUnauthorized(): int|JsonResponse { $userId = (int) (auth()->id() ?? 0); if ($userId <= 0) { return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED); } return $userId; } }