get('per_page', 10); $page = $request->get('page', 1); $filter = $request->get('filter', 'all'); // all, unread, read $query = $user->notifications(); // Apply filter switch ($filter) { case 'unread': $query->whereNull('read_at'); break; case 'read': $query->whereNotNull('read_at'); break; default: // Show all notifications break; } $notifications = $query->orderBy('created_at', 'desc') ->paginate($perPage, ['*'], 'page', $page); // Transform notifications to match frontend format $transformedNotifications = $notifications->map(function ($notification) { $data = $notification->data; // Detect notification category (for internal categorization) $notificationCategory = $this->detectNotificationCategory($data); // Get display type (action type for KJC Repair, or original type for others) $displayType = $this->getDisplayType($data, $notificationCategory); return [ 'id' => $notification->id, 'type' => $displayType, 'title' => $this->getNotificationTitle($data, $notificationCategory), 'message' => $this->getNotificationMessage($data, $notificationCategory), 'is_read' => $notification->read_at !== null, 'created_at' => $notification->created_at->format('Y-m-d H:i:s'), 'time_ago' => $notification->created_at->diffForHumans(), 'icon' => $this->getNotificationIcon($notificationCategory), 'color' => $this->getNotificationColor($notificationCategory), 'navigation' => $this->getNotificationNavigation($data, $notificationCategory), 'data' => $data ]; }); return response()->json([ 'success' => true, 'data' => $transformedNotifications, 'pagination' => [ 'current_page' => $notifications->currentPage(), 'last_page' => $notifications->lastPage(), 'per_page' => $notifications->perPage(), 'total' => $notifications->total(), 'has_more' => $notifications->hasMorePages() ], 'unread_count' => $user->unreadNotifications()->count() ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Failed to fetch notifications: ' . $e->getMessage() ], 500); } } /** * Mark notification as read */ public function markAsRead($id): JsonResponse { try { $user = Auth::user(); $notification = $user->notifications()->find($id); if (!$notification) { return response()->json([ 'success' => false, 'message' => 'Notifikasi tidak ditemukan' ], 404); } $notification->markAsRead(); return response()->json([ 'success' => true, 'message' => 'Notifikasi ditandakan sebagai telah dibaca' ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Gagal menandakan notifikasi sebagai telah dibaca: ' . $e->getMessage() ], 500); } } /** * Mark all notifications as read */ public function markAllAsRead(): JsonResponse { try { $user = Auth::user(); $user->unreadNotifications->markAsRead(); return response()->json([ 'success' => true, 'message' => 'Semua notifikasi ditandakan sebagai telah dibaca' ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Gagal menandakan semua notifikasi sebagai telah dibaca: ' . $e->getMessage() ], 500); } } /** * Get notification count */ public function getCount(): JsonResponse { try { $user = Auth::user(); $unreadCount = $user->unreadNotifications()->count(); return response()->json([ 'success' => true, 'unread_count' => $unreadCount ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Gagal mendapatkan bilangan notifikasi: ' . $e->getMessage() ], 500); } } /** * Detect notification category from data (for internal categorization) */ private function detectNotificationCategory($data): string { // Check if it's a KJC Repair notification if (isset($data['kjc_repair_id'])) { return 'kjc_repair'; } // Check if it's a KJC Temporary Loan notification if (isset($data['kjc_temporary_loan_id'])) { return 'kjc_temporary_loan'; } // Check if it's a User Activation notification if (isset($data['user_id']) && isset($data['type']) && $data['type'] === 'user_activation_required') { return 'user_activation'; } // Check if it's a Feedback notification if (isset($data['feedback_id'])) { return 'feedback'; } // Check for other notification types if (isset($data['type'])) { return $data['type']; } return 'general'; } /** * Get display type for frontend (action type for KJC Repair/Temporary Loan, original type for others) */ private function getDisplayType($data, $category): string { // For KJC Repair and Temporary Loan notifications, return the action type (next_approval, approved, etc.) if (($category === 'kjc_repair' || $category === 'kjc_temporary_loan') && isset($data['type'])) { return $data['type']; } // For User Activation notifications, return the type if ($category === 'user_activation' && isset($data['type'])) { return $data['type']; } // For Feedback notifications, return the type if ($category === 'feedback' && isset($data['type'])) { return $data['type']; } // For other notifications, return the category return $category; } /** * Get notification title based on category and data */ private function getNotificationTitle($data, $notificationCategory): string { if ($notificationCategory === 'kjc_repair') { $repairType = $data['type'] ?? 'general'; switch ($repairType) { case 'next_approval': return 'Pembaikan KJC - Permohonan Disemak'; case 'approved': return 'Pembaikan KJC - Disetujui'; case 'rejected': return 'Pembaikan KJC - Ditolak'; case 'returned_for_revision': return 'Pembaikan KJC - Dikembalikan untuk semakan semula'; default: return 'Notifikasi Pembaikan KJC'; } } if ($notificationCategory === 'kjc_temporary_loan') { $loanType = $data['type'] ?? 'general'; switch ($loanType) { case 'next_approval': return 'Pinjaman Sementara KJC - Permohonan Disemak'; case 'approved': return 'Pinjaman Sementara KJC - Disetujui'; case 'rejected': return 'Pinjaman Sementara KJC - Ditolak'; case 'returned_for_revision': return 'Pinjaman Sementara KJC - Dikembalikan untuk semakan semula'; default: return 'Notifikasi Pinjaman Sementara KJC'; } } if ($notificationCategory === 'user_activation') { return 'Pengaktifan Pengguna Diperlukan'; } if ($notificationCategory === 'feedback') { return 'Maklum Balas Baru Diterima'; } switch ($notificationCategory) { case 'report_generation': return 'Penyata Mingguan Dicipta'; case 'system': return 'Notifikasi Sistem'; default: return 'Notifikasi'; } } /** * Get notification message based on category and data */ private function getNotificationMessage($data, $notificationCategory): string { // If message is already set, use it if (!empty($data['message'])) { return $data['message']; } // Generate message for KJC Repair notifications if ($notificationCategory === 'kjc_repair') { $repairType = $data['type'] ?? 'general'; $repairId = $data['kjc_repair_id'] ?? 'N/A'; $assetName = $data['asset_name'] ?? 'Unknown'; $unitName = $data['unit_name'] ?? 'Unknown'; switch ($repairType) { case 'next_approval': return "Permohonan pembaikan KJC perlu disemak oleh anda. ID Permohonan: {$repairId}, Asset: {$assetName}, Unit: {$unitName}"; case 'approved': return "Permohonan pembaikan KJC telah disetujui. ID Permohonan: {$repairId}, Asset: {$assetName}, Unit: {$unitName}"; case 'rejected': return "Permohonan pembaikan KJC telah ditolak. ID Permohonan: {$repairId}, Asset: {$assetName}, Unit: {$unitName}"; case 'returned_for_revision': return "Permohonan pembaikan KJC telah dikembalikan untuk semakan semula. ID Permohonan: {$repairId}, Asset: {$assetName}, Unit: {$unitName}"; default: return "Notifikasi berkaitan permohonan pembaikan KJC. ID Permohonan: {$repairId}"; } } // Generate message for KJC Temporary Loan notifications if ($notificationCategory === 'kjc_temporary_loan') { $loanType = $data['type'] ?? 'general'; $assetName = $data['asset_name'] ?? 'Unknown'; $originalUnitName = $data['original_unit_name'] ?? 'Unknown'; $borrowerUnitName = $data['borrower_unit_name'] ?? 'Unknown'; switch ($loanType) { case 'next_approval': return "Permohonan pinjaman sementara KJC perlu disemak oleh anda, Asset: {$assetName}, Pasukan Asal: {$originalUnitName}, Pasukan Peminjam: {$borrowerUnitName}"; case 'approved': return "Permohonan pinjaman sementara KJC telah disetujui, Asset: {$assetName}, Pasukan Asal: {$originalUnitName}, Pasukan Peminjam: {$borrowerUnitName}"; case 'rejected': return "Permohonan pinjaman sementara KJC telah ditolak, Asset: {$assetName}, Pasukan Asal: {$originalUnitName}, Pasukan Peminjam: {$borrowerUnitName}"; case 'returned_for_revision': return "Permohonan pinjaman sementara KJC telah dikembalikan untuk semakan semula, Asset: {$assetName}, Pasukan Asal: {$originalUnitName}, Pasukan Peminjam: {$borrowerUnitName}"; default: return "Notifikasi berkaitan permohonan pinjaman sementara KJC, Asset: {$assetName}, Pasukan Asal: {$originalUnitName}, Pasukan Peminjam: {$borrowerUnitName}"; } } // Generate message for User Activation notifications if ($notificationCategory === 'user_activation') { // If message is already set, use it if (!empty($data['message'])) { return $data['message']; } $userName = $data['user_name'] ?? 'Unknown'; $userEmail = $data['user_email'] ?? 'Unknown'; $userArmyNumber = $data['user_army_number'] ?? 'Unknown'; $unitName = $data['user_unit_name'] ?? 'Unknown'; return "Pengguna baru memerlukan pengaktifan. Nama: {$userName}, Email: {$userEmail}, No. Tentera: {$userArmyNumber}, Unit: {$unitName}"; } // Generate message for Feedback notifications if ($notificationCategory === 'feedback') { // If message is already set, use it if (!empty($data['message'])) { return $data['message']; } $feedbackTitle = $data['feedback_title'] ?? 'Unknown'; $feedbackType = $data['feedback_type'] ?? 'Unknown'; $feedbackPriority = $data['feedback_priority'] ?? 'normal'; $userName = $data['user_name'] ?? 'Anonymous'; $feedbackId = $data['feedback_id'] ?? 'N/A'; return "Maklum balas baru telah diterima. ID: {$feedbackId}, Tajuk: {$feedbackTitle}, Jenis: {$feedbackType}, Keutamaan: {$feedbackPriority}, Pengguna: {$userName}"; } return 'No message available'; } /** * Get notification icon based on type */ private function getNotificationIcon($type): string { switch ($type) { case 'report_generation': return 'mdi-file-document'; case 'kjc_repair': return 'mdi-tools'; case 'kjc_temporary_loan': return 'mdi-handshake'; case 'user_activation': case 'user_activation_required': return 'mdi-account-plus'; case 'feedback': case 'feedback_submitted': return 'mdi-message-alert'; case 'system': return 'mdi-cog'; default: return 'mdi-bell'; } } /** * Get notification color based on type */ private function getNotificationColor($type): string { switch ($type) { case 'report_generation': return 'success'; case 'kjc_repair': return 'warning'; case 'kjc_temporary_loan': return 'info'; case 'user_activation': case 'user_activation_required': return 'purple'; case 'feedback': case 'feedback_submitted': return 'orange'; case 'system': return 'info'; default: return 'primary'; } } /** * Get notification navigation data based on category */ private function getNotificationNavigation($data, $notificationCategory): array { if ($notificationCategory === 'kjc_repair') { $repairId = $data['kjc_repair_id'] ?? null; return [ 'route' => '/kjcrepairs', 'params' => [], 'query' => $repairId ? ['id' => $repairId] : [] ]; } if ($notificationCategory === 'kjc_temporary_loan') { $loanId = $data['kjc_temporary_loan_id'] ?? null; return [ 'route' => '/kjctemporaryloans', 'params' => [], 'query' => $loanId ? ['id' => $loanId] : [] ]; } if ($notificationCategory === 'user_activation') { $userId = $data['user_id'] ?? null; return [ 'route' => '/users', 'params' => [], 'query' => $userId ? ['id' => $userId] : [] ]; } if ($notificationCategory === 'feedback') { $feedbackId = $data['feedback_id'] ?? null; return [ 'route' => '/feedback', 'params' => [], 'query' => $feedbackId ? ['id' => $feedbackId] : [] ]; } switch ($notificationCategory) { case 'report_generation': return [ 'route' => '/kjcreports', 'params' => [], 'query' => [] ]; case 'system': return [ 'route' => '/dashboard', 'params' => [], 'query' => [] ]; default: return [ 'route' => '/dashboard', 'params' => [], 'query' => [] ]; } } }