import 'package:get/get.dart'; import 'package:logger/logger.dart'; import 'package:marco/controller/dashboard/attendance_screen_controller.dart'; import 'package:marco/controller/dashboard/daily_task_controller.dart'; import 'package:marco/controller/task_planing/daily_task_planing_controller.dart'; import 'package:marco/controller/expense/expense_screen_controller.dart'; import 'package:marco/controller/expense/expense_detail_controller.dart'; /// Handles incoming FCM notification actions and updates UI/controllers. class NotificationActionHandler { static final Logger _logger = Logger(); /// Main entry point — call this for any notification `data` map. static void handle(Map data) { _logger.i('📲 Handling notification action: $data'); if (data.isEmpty) { _logger.w('âš ī¸ Empty notification data received.'); return; } final type = data['type']; final action = data['Action']; final keyword = data['Keyword']; if (type != null) { _handleByType(type, data); } else if (keyword != null) { _handleByKeyword(keyword, action, data); } else { _logger.w('âš ī¸ Unhandled notification: $data'); } } /// Handle notification if identified by `type` static void _handleByType(String type, Map data) { switch (type) { case 'expense_updated': // No specific handler yet break; case 'attendance_updated': _handleAttendanceUpdated(data); break; default: _logger.w('âš ī¸ Unknown notification type: $type'); } } /// Handle notification if identified by `keyword` static void _handleByKeyword( String keyword, String? action, Map data) { switch (keyword) { case 'Attendance': if (_isAttendanceAction(action)) { _handleAttendanceUpdated(data); } break; case 'Report_Task': _handleTaskUpdated(data, isComment: false); break; case 'Task_Comment': _handleTaskUpdated(data, isComment: true); break; case 'Expenses_Modified': _handleExpenseUpdated(data); break; // ✅ New cases case 'Task_Modified': case 'WorkArea_Modified': case 'Floor_Modified': case 'Building_Modified': _handleTaskPlanningUpdated(data); break; default: _logger.w('âš ī¸ Unhandled notification keyword: $keyword'); } } static void _handleTaskPlanningUpdated(Map data) { final projectId = data['ProjectId']; if (projectId == null) { _logger.w("âš ī¸ TaskPlanning update received without ProjectId: $data"); return; } _safeControllerUpdate( onFound: (controller) { controller.fetchTaskData(projectId); }, notFoundMessage: 'âš ī¸ DailyTaskPlaningController not found, cannot refresh.', successMessage: '✅ DailyTaskPlaningController refreshed from notification.', ); } /// Validates the set of allowed Attendance actions static bool _isAttendanceAction(String? action) { const validActions = { 'CHECK_IN', 'CHECK_OUT', 'REQUEST_REGULARIZE', 'REQUEST_DELETE', 'REGULARIZE', 'REGULARIZE_REJECT' }; return validActions.contains(action); } static void _handleExpenseUpdated(Map data) { final expenseId = data['ExpenseId']; if (expenseId == null) { _logger.w("âš ī¸ Expense update received without ExpenseId: $data"); return; } // Update Expense List _safeControllerUpdate( onFound: (controller) async { await controller.fetchExpenses(); }, notFoundMessage: 'âš ī¸ ExpenseController not found, cannot refresh list.', successMessage: '✅ ExpenseController refreshed from expense notification.', ); // Update Expense Detail (if open and matches this expenseId) _safeControllerUpdate( onFound: (controller) async { // only refresh if the open screen is for this expense if (controller.expense.value?.id == expenseId) { await controller.fetchExpenseDetails(); _logger .i("✅ ExpenseDetailController refreshed for Expense $expenseId"); } }, notFoundMessage: 'â„šī¸ ExpenseDetailController not active, skipping.', successMessage: '✅ ExpenseDetailController checked for refresh.', ); } static void _handleAttendanceUpdated(Map data) { _safeControllerUpdate( onFound: (controller) => controller.refreshDataFromNotification( projectId: data['ProjectId'], ), notFoundMessage: 'âš ī¸ AttendanceController not found, cannot update.', successMessage: '✅ AttendanceController refreshed from notification.', ); } static void _handleTaskUpdated(Map data, {required bool isComment}) { _safeControllerUpdate( onFound: (controller) => controller.refreshTasksFromNotification( projectId: data['ProjectId'], taskAllocationId: data['TaskAllocationId'], ), notFoundMessage: 'âš ī¸ DailyTaskController not found, cannot update.', successMessage: '✅ DailyTaskController refreshed from notification.', ); } /// Generic reusable method for safe GetX controller access + log handling static void _safeControllerUpdate({ required void Function(T controller) onFound, required String notFoundMessage, required String successMessage, }) { try { final controller = Get.find(); onFound(controller); _logger.i(successMessage); } catch (e) { _logger.w(notFoundMessage); } } }