diff --git a/lib/controller/dashboard/dashboard_controller.dart b/lib/controller/dashboard/dashboard_controller.dart index 91d812a..72f2331 100644 --- a/lib/controller/dashboard/dashboard_controller.dart +++ b/lib/controller/dashboard/dashboard_controller.dart @@ -70,9 +70,9 @@ class DashboardController extends GetxController { ever(projectSelectedRange, (_) => fetchProjectProgress()); } - /// ========================= - /// Helper Methods - /// ========================= + // ========================= + // Helper Methods + // ========================= int _getDaysFromRange(String range) { switch (range) { case '7D': @@ -114,21 +114,28 @@ class DashboardController extends GetxController { logSafe('Project chart view toggled to: $isChart', level: LogLevel.debug); } - /// ========================= - /// Manual refresh - /// ========================= + // ========================= + // Manual Refresh Methods + // ========================= Future refreshDashboard() async { logSafe('Manual dashboard refresh triggered.', level: LogLevel.debug); await fetchAllDashboardData(); } - /// ========================= - /// Fetch all dashboard data - /// ========================= + Future refreshAttendance() async => fetchRoleWiseAttendance(); + Future refreshTasks() async { + final projectId = projectController.selectedProjectId.value; + if (projectId.isNotEmpty) await fetchDashboardTasks(projectId: projectId); + } + + Future refreshProjects() async => fetchProjectProgress(); + + // ========================= + // Fetch All Dashboard Data + // ========================= Future fetchAllDashboardData() async { final String projectId = projectController.selectedProjectId.value; - // Skip fetching if no project is selected if (projectId.isEmpty) { logSafe('No project selected. Skipping dashboard API calls.', level: LogLevel.warning); @@ -143,17 +150,15 @@ class DashboardController extends GetxController { ]); } - /// ========================= - /// API Calls - /// ========================= + // ========================= + // API Calls + // ========================= Future fetchRoleWiseAttendance() async { final String projectId = projectController.selectedProjectId.value; - if (projectId.isEmpty) return; try { isAttendanceLoading.value = true; - final List? response = await ApiService.getDashboardAttendanceOverview( projectId, getAttendanceDays()); @@ -179,16 +184,12 @@ class DashboardController extends GetxController { Future fetchProjectProgress() async { final String projectId = projectController.selectedProjectId.value; - if (projectId.isEmpty) return; try { isProjectLoading.value = true; - final response = await ApiService.getProjectProgress( - projectId: projectId, - days: getProjectDays(), - ); + projectId: projectId, days: getProjectDays()); if (response != null && response.success) { projectChartData.value = @@ -208,11 +209,10 @@ class DashboardController extends GetxController { } Future fetchDashboardTasks({required String projectId}) async { - if (projectId.isEmpty) return; // Skip if empty + if (projectId.isEmpty) return; try { isTasksLoading.value = true; - final response = await ApiService.getDashboardTasks(projectId: projectId); if (response != null && response.success) { @@ -235,11 +235,10 @@ class DashboardController extends GetxController { } Future fetchDashboardTeams({required String projectId}) async { - if (projectId.isEmpty) return; // Skip if empty + if (projectId.isEmpty) return; try { isTeamsLoading.value = true; - final response = await ApiService.getDashboardTeams(projectId: projectId); if (response != null && response.success) { diff --git a/lib/helpers/services/notification_action_handler.dart b/lib/helpers/services/notification_action_handler.dart index 4c89f24..a8073f3 100644 --- a/lib/helpers/services/notification_action_handler.dart +++ b/lib/helpers/services/notification_action_handler.dart @@ -9,8 +9,9 @@ import 'package:marco/controller/expense/expense_detail_controller.dart'; import 'package:marco/controller/directory/directory_controller.dart'; import 'package:marco/controller/directory/notes_controller.dart'; import 'package:marco/controller/document/user_document_controller.dart'; -import 'package:marco/helpers/utils/permission_constants.dart'; import 'package:marco/controller/document/document_details_controller.dart'; +import 'package:marco/controller/dashboard/dashboard_controller.dart'; +import 'package:marco/helpers/utils/permission_constants.dart'; /// Handles incoming FCM notification actions and updates UI/controllers. class NotificationActionHandler { @@ -46,6 +47,10 @@ class NotificationActionHandler { break; case 'attendance_updated': _handleAttendanceUpdated(data); + _handleDashboardUpdate(data); // refresh dashboard attendance + break; + case 'dashboard_update': + _handleDashboardUpdate(data); // full dashboard refresh break; default: _logger.w('âš ī¸ Unknown notification type: $type'); @@ -60,16 +65,19 @@ class NotificationActionHandler { case 'Attendance': if (_isAttendanceAction(action)) { _handleAttendanceUpdated(data); + _handleDashboardUpdate(data); } break; /// 🔹 Tasks case 'Report_Task': _handleTaskUpdated(data, isComment: false); + _handleDashboardUpdate(data); break; case 'Task_Comment': _handleTaskUpdated(data, isComment: true); + _handleDashboardUpdate(data); break; case 'Task_Modified': @@ -77,11 +85,13 @@ class NotificationActionHandler { case 'Floor_Modified': case 'Building_Modified': _handleTaskPlanningUpdated(data); + _handleDashboardUpdate(data); break; /// 🔹 Expenses case 'Expenses_Modified': _handleExpenseUpdated(data); + _handleDashboardUpdate(data); break; /// 🔹 Documents @@ -198,59 +208,55 @@ class NotificationActionHandler { } /// ---------------------- DOCUMENT HANDLER ---------------------- - /// ---------------------- DOCUMENT HANDLER ---------------------- -static void _handleDocumentModified(Map data) { - late String entityTypeId; - late String entityId; - String? documentId = data['DocumentId']; + static void _handleDocumentModified(Map data) { + late String entityTypeId; + late String entityId; + String? documentId = data['DocumentId']; - if (data['Keyword'] == 'Employee_Document_Modified') { - entityTypeId = Permissions.employeeEntity; - entityId = data['EmployeeId'] ?? ''; - } else if (data['Keyword'] == 'Project_Document_Modified') { - entityTypeId = Permissions.projectEntity; - entityId = data['ProjectId'] ?? ''; - } else { - _logger.w("âš ī¸ Document update received with unknown keyword: $data"); - return; - } + if (data['Keyword'] == 'Employee_Document_Modified') { + entityTypeId = Permissions.employeeEntity; + entityId = data['EmployeeId'] ?? ''; + } else if (data['Keyword'] == 'Project_Document_Modified') { + entityTypeId = Permissions.projectEntity; + entityId = data['ProjectId'] ?? ''; + } else { + _logger.w("âš ī¸ Document update received with unknown keyword: $data"); + return; + } - if (entityId.isEmpty) { - _logger.w("âš ī¸ Document update missing entityId: $data"); - return; - } + if (entityId.isEmpty) { + _logger.w("âš ī¸ Document update missing entityId: $data"); + return; + } - // 🔹 Refresh document list - _safeControllerUpdate( - onFound: (controller) async { - await controller.fetchDocuments( - entityTypeId: entityTypeId, - entityId: entityId, - reset: true, - ); - }, - notFoundMessage: 'âš ī¸ DocumentController not found, cannot refresh list.', - successMessage: '✅ DocumentController refreshed from notification.', - ); - - // 🔹 Refresh document details (if opened) - if (documentId != null) { - _safeControllerUpdate( + _safeControllerUpdate( onFound: (controller) async { - if (controller.documentDetails.value?.data?.id == documentId) { - await controller.fetchDocumentDetails(documentId); - _logger.i("✅ DocumentDetailsController refreshed for Document $documentId"); - } + await controller.fetchDocuments( + entityTypeId: entityTypeId, + entityId: entityId, + reset: true, + ); }, - notFoundMessage: 'â„šī¸ DocumentDetailsController not active, skipping.', - successMessage: '✅ DocumentDetailsController checked for refresh.', + notFoundMessage: 'âš ī¸ DocumentController not found, cannot refresh list.', + successMessage: '✅ DocumentController refreshed from notification.', ); - } -} + if (documentId != null) { + _safeControllerUpdate( + onFound: (controller) async { + if (controller.documentDetails.value?.data?.id == documentId) { + await controller.fetchDocumentDetails(documentId); + _logger.i( + "✅ DocumentDetailsController refreshed for Document $documentId"); + } + }, + notFoundMessage: 'â„šī¸ DocumentDetailsController not active, skipping.', + successMessage: '✅ DocumentDetailsController checked for refresh.', + ); + } + } /// ---------------------- DIRECTORY HANDLERS ---------------------- - static void _handleContactModified(Map data) { _safeControllerUpdate( onFound: (controller) => controller.fetchContacts(), @@ -296,6 +302,32 @@ static void _handleDocumentModified(Map data) { ); } + /// ---------------------- DASHBOARD HANDLER ---------------------- + static void _handleDashboardUpdate(Map data) { + _safeControllerUpdate( + onFound: (controller) async { + final type = data['type'] ?? ''; + switch (type) { + case 'attendance_updated': + await controller.fetchRoleWiseAttendance(); + break; + case 'task_updated': + await controller.fetchDashboardTasks( + projectId: controller.projectController.selectedProjectId.value); + break; + case 'project_progress_update': + await controller.fetchProjectProgress(); + break; + case 'full_dashboard_refresh': + default: + await controller.refreshDashboard(); + } + }, + notFoundMessage: 'âš ī¸ DashboardController not found, cannot refresh.', + successMessage: '✅ DashboardController refreshed from notification.', + ); + } + /// ---------------------- UTILITY ---------------------- static void _safeControllerUpdate({