feat: Enhance dashboard refresh logic; add handling for various notification types and improve method organization
This commit is contained in:
parent
7d5d2b5bf4
commit
25b20fedda
@ -70,9 +70,9 @@ class DashboardController extends GetxController {
|
|||||||
ever(projectSelectedRange, (_) => fetchProjectProgress());
|
ever(projectSelectedRange, (_) => fetchProjectProgress());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// =========================
|
// =========================
|
||||||
/// Helper Methods
|
// Helper Methods
|
||||||
/// =========================
|
// =========================
|
||||||
int _getDaysFromRange(String range) {
|
int _getDaysFromRange(String range) {
|
||||||
switch (range) {
|
switch (range) {
|
||||||
case '7D':
|
case '7D':
|
||||||
@ -114,21 +114,28 @@ class DashboardController extends GetxController {
|
|||||||
logSafe('Project chart view toggled to: $isChart', level: LogLevel.debug);
|
logSafe('Project chart view toggled to: $isChart', level: LogLevel.debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// =========================
|
// =========================
|
||||||
/// Manual refresh
|
// Manual Refresh Methods
|
||||||
/// =========================
|
// =========================
|
||||||
Future<void> refreshDashboard() async {
|
Future<void> refreshDashboard() async {
|
||||||
logSafe('Manual dashboard refresh triggered.', level: LogLevel.debug);
|
logSafe('Manual dashboard refresh triggered.', level: LogLevel.debug);
|
||||||
await fetchAllDashboardData();
|
await fetchAllDashboardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// =========================
|
Future<void> refreshAttendance() async => fetchRoleWiseAttendance();
|
||||||
/// Fetch all dashboard data
|
Future<void> refreshTasks() async {
|
||||||
/// =========================
|
final projectId = projectController.selectedProjectId.value;
|
||||||
|
if (projectId.isNotEmpty) await fetchDashboardTasks(projectId: projectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> refreshProjects() async => fetchProjectProgress();
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// Fetch All Dashboard Data
|
||||||
|
// =========================
|
||||||
Future<void> fetchAllDashboardData() async {
|
Future<void> fetchAllDashboardData() async {
|
||||||
final String projectId = projectController.selectedProjectId.value;
|
final String projectId = projectController.selectedProjectId.value;
|
||||||
|
|
||||||
// Skip fetching if no project is selected
|
|
||||||
if (projectId.isEmpty) {
|
if (projectId.isEmpty) {
|
||||||
logSafe('No project selected. Skipping dashboard API calls.',
|
logSafe('No project selected. Skipping dashboard API calls.',
|
||||||
level: LogLevel.warning);
|
level: LogLevel.warning);
|
||||||
@ -143,17 +150,15 @@ class DashboardController extends GetxController {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// =========================
|
// =========================
|
||||||
/// API Calls
|
// API Calls
|
||||||
/// =========================
|
// =========================
|
||||||
Future<void> fetchRoleWiseAttendance() async {
|
Future<void> fetchRoleWiseAttendance() async {
|
||||||
final String projectId = projectController.selectedProjectId.value;
|
final String projectId = projectController.selectedProjectId.value;
|
||||||
|
|
||||||
if (projectId.isEmpty) return;
|
if (projectId.isEmpty) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isAttendanceLoading.value = true;
|
isAttendanceLoading.value = true;
|
||||||
|
|
||||||
final List<dynamic>? response =
|
final List<dynamic>? response =
|
||||||
await ApiService.getDashboardAttendanceOverview(
|
await ApiService.getDashboardAttendanceOverview(
|
||||||
projectId, getAttendanceDays());
|
projectId, getAttendanceDays());
|
||||||
@ -179,16 +184,12 @@ class DashboardController extends GetxController {
|
|||||||
|
|
||||||
Future<void> fetchProjectProgress() async {
|
Future<void> fetchProjectProgress() async {
|
||||||
final String projectId = projectController.selectedProjectId.value;
|
final String projectId = projectController.selectedProjectId.value;
|
||||||
|
|
||||||
if (projectId.isEmpty) return;
|
if (projectId.isEmpty) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isProjectLoading.value = true;
|
isProjectLoading.value = true;
|
||||||
|
|
||||||
final response = await ApiService.getProjectProgress(
|
final response = await ApiService.getProjectProgress(
|
||||||
projectId: projectId,
|
projectId: projectId, days: getProjectDays());
|
||||||
days: getProjectDays(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response != null && response.success) {
|
if (response != null && response.success) {
|
||||||
projectChartData.value =
|
projectChartData.value =
|
||||||
@ -208,11 +209,10 @@ class DashboardController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchDashboardTasks({required String projectId}) async {
|
Future<void> fetchDashboardTasks({required String projectId}) async {
|
||||||
if (projectId.isEmpty) return; // Skip if empty
|
if (projectId.isEmpty) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isTasksLoading.value = true;
|
isTasksLoading.value = true;
|
||||||
|
|
||||||
final response = await ApiService.getDashboardTasks(projectId: projectId);
|
final response = await ApiService.getDashboardTasks(projectId: projectId);
|
||||||
|
|
||||||
if (response != null && response.success) {
|
if (response != null && response.success) {
|
||||||
@ -235,11 +235,10 @@ class DashboardController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchDashboardTeams({required String projectId}) async {
|
Future<void> fetchDashboardTeams({required String projectId}) async {
|
||||||
if (projectId.isEmpty) return; // Skip if empty
|
if (projectId.isEmpty) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isTeamsLoading.value = true;
|
isTeamsLoading.value = true;
|
||||||
|
|
||||||
final response = await ApiService.getDashboardTeams(projectId: projectId);
|
final response = await ApiService.getDashboardTeams(projectId: projectId);
|
||||||
|
|
||||||
if (response != null && response.success) {
|
if (response != null && response.success) {
|
||||||
|
@ -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/directory_controller.dart';
|
||||||
import 'package:marco/controller/directory/notes_controller.dart';
|
import 'package:marco/controller/directory/notes_controller.dart';
|
||||||
import 'package:marco/controller/document/user_document_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/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.
|
/// Handles incoming FCM notification actions and updates UI/controllers.
|
||||||
class NotificationActionHandler {
|
class NotificationActionHandler {
|
||||||
@ -46,6 +47,10 @@ class NotificationActionHandler {
|
|||||||
break;
|
break;
|
||||||
case 'attendance_updated':
|
case 'attendance_updated':
|
||||||
_handleAttendanceUpdated(data);
|
_handleAttendanceUpdated(data);
|
||||||
|
_handleDashboardUpdate(data); // refresh dashboard attendance
|
||||||
|
break;
|
||||||
|
case 'dashboard_update':
|
||||||
|
_handleDashboardUpdate(data); // full dashboard refresh
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_logger.w('⚠️ Unknown notification type: $type');
|
_logger.w('⚠️ Unknown notification type: $type');
|
||||||
@ -60,16 +65,19 @@ class NotificationActionHandler {
|
|||||||
case 'Attendance':
|
case 'Attendance':
|
||||||
if (_isAttendanceAction(action)) {
|
if (_isAttendanceAction(action)) {
|
||||||
_handleAttendanceUpdated(data);
|
_handleAttendanceUpdated(data);
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/// 🔹 Tasks
|
/// 🔹 Tasks
|
||||||
case 'Report_Task':
|
case 'Report_Task':
|
||||||
_handleTaskUpdated(data, isComment: false);
|
_handleTaskUpdated(data, isComment: false);
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Task_Comment':
|
case 'Task_Comment':
|
||||||
_handleTaskUpdated(data, isComment: true);
|
_handleTaskUpdated(data, isComment: true);
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Task_Modified':
|
case 'Task_Modified':
|
||||||
@ -77,11 +85,13 @@ class NotificationActionHandler {
|
|||||||
case 'Floor_Modified':
|
case 'Floor_Modified':
|
||||||
case 'Building_Modified':
|
case 'Building_Modified':
|
||||||
_handleTaskPlanningUpdated(data);
|
_handleTaskPlanningUpdated(data);
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/// 🔹 Expenses
|
/// 🔹 Expenses
|
||||||
case 'Expenses_Modified':
|
case 'Expenses_Modified':
|
||||||
_handleExpenseUpdated(data);
|
_handleExpenseUpdated(data);
|
||||||
|
_handleDashboardUpdate(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/// 🔹 Documents
|
/// 🔹 Documents
|
||||||
@ -198,59 +208,55 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ---------------------- DOCUMENT HANDLER ----------------------
|
/// ---------------------- DOCUMENT HANDLER ----------------------
|
||||||
/// ---------------------- DOCUMENT HANDLER ----------------------
|
static void _handleDocumentModified(Map<String, dynamic> data) {
|
||||||
static void _handleDocumentModified(Map<String, dynamic> data) {
|
late String entityTypeId;
|
||||||
late String entityTypeId;
|
late String entityId;
|
||||||
late String entityId;
|
String? documentId = data['DocumentId'];
|
||||||
String? documentId = data['DocumentId'];
|
|
||||||
|
|
||||||
if (data['Keyword'] == 'Employee_Document_Modified') {
|
if (data['Keyword'] == 'Employee_Document_Modified') {
|
||||||
entityTypeId = Permissions.employeeEntity;
|
entityTypeId = Permissions.employeeEntity;
|
||||||
entityId = data['EmployeeId'] ?? '';
|
entityId = data['EmployeeId'] ?? '';
|
||||||
} else if (data['Keyword'] == 'Project_Document_Modified') {
|
} else if (data['Keyword'] == 'Project_Document_Modified') {
|
||||||
entityTypeId = Permissions.projectEntity;
|
entityTypeId = Permissions.projectEntity;
|
||||||
entityId = data['ProjectId'] ?? '';
|
entityId = data['ProjectId'] ?? '';
|
||||||
} else {
|
} else {
|
||||||
_logger.w("⚠️ Document update received with unknown keyword: $data");
|
_logger.w("⚠️ Document update received with unknown keyword: $data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityId.isEmpty) {
|
if (entityId.isEmpty) {
|
||||||
_logger.w("⚠️ Document update missing entityId: $data");
|
_logger.w("⚠️ Document update missing entityId: $data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 Refresh document list
|
_safeControllerUpdate<DocumentController>(
|
||||||
_safeControllerUpdate<DocumentController>(
|
|
||||||
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<DocumentDetailsController>(
|
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
if (controller.documentDetails.value?.data?.id == documentId) {
|
await controller.fetchDocuments(
|
||||||
await controller.fetchDocumentDetails(documentId);
|
entityTypeId: entityTypeId,
|
||||||
_logger.i("✅ DocumentDetailsController refreshed for Document $documentId");
|
entityId: entityId,
|
||||||
}
|
reset: true,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
notFoundMessage: 'ℹ️ DocumentDetailsController not active, skipping.',
|
notFoundMessage: '⚠️ DocumentController not found, cannot refresh list.',
|
||||||
successMessage: '✅ DocumentDetailsController checked for refresh.',
|
successMessage: '✅ DocumentController refreshed from notification.',
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (documentId != null) {
|
||||||
|
_safeControllerUpdate<DocumentDetailsController>(
|
||||||
|
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 ----------------------
|
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
||||||
|
|
||||||
static void _handleContactModified(Map<String, dynamic> data) {
|
static void _handleContactModified(Map<String, dynamic> data) {
|
||||||
_safeControllerUpdate<DirectoryController>(
|
_safeControllerUpdate<DirectoryController>(
|
||||||
onFound: (controller) => controller.fetchContacts(),
|
onFound: (controller) => controller.fetchContacts(),
|
||||||
@ -296,6 +302,32 @@ static void _handleDocumentModified(Map<String, dynamic> data) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ---------------------- DASHBOARD HANDLER ----------------------
|
||||||
|
static void _handleDashboardUpdate(Map<String, dynamic> data) {
|
||||||
|
_safeControllerUpdate<DashboardController>(
|
||||||
|
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 ----------------------
|
/// ---------------------- UTILITY ----------------------
|
||||||
|
|
||||||
static void _safeControllerUpdate<T>({
|
static void _safeControllerUpdate<T>({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user