304 lines
9.8 KiB
Dart
304 lines
9.8 KiB
Dart
import 'package:get/get.dart';
|
||
import 'package:logger/logger.dart';
|
||
|
||
import 'package:marco/controller/attendance/attendance_screen_controller.dart';
|
||
import 'package:marco/controller/task_planning/daily_task_controller.dart';
|
||
import 'package:marco/controller/task_Planning/daily_task_Planning_controller.dart';
|
||
import 'package:marco/controller/expense/expense_screen_controller.dart';
|
||
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/controller/document/document_details_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<String, dynamic> 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<String, dynamic> data) {
|
||
switch (type) {
|
||
case 'expense_updated':
|
||
_handleExpenseUpdated(data);
|
||
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<String, dynamic> data) {
|
||
switch (keyword) {
|
||
/// 🔹 Attendance
|
||
case 'Attendance':
|
||
if (_isAttendanceAction(action)) {
|
||
_handleAttendanceUpdated(data);
|
||
}
|
||
break;
|
||
|
||
/// 🔹 Tasks
|
||
case 'Report_Task':
|
||
_handleTaskUpdated(data, isComment: false);
|
||
break;
|
||
|
||
case 'Task_Comment':
|
||
_handleTaskUpdated(data, isComment: true);
|
||
break;
|
||
|
||
case 'Task_Modified':
|
||
case 'WorkArea_Modified':
|
||
case 'Floor_Modified':
|
||
case 'Building_Modified':
|
||
_handleTaskPlanningUpdated(data);
|
||
break;
|
||
|
||
/// 🔹 Expenses
|
||
case 'Expenses_Modified':
|
||
_handleExpenseUpdated(data);
|
||
break;
|
||
|
||
/// 🔹 Documents
|
||
case 'Employee_Document_Modified':
|
||
case 'Project_Document_Modified':
|
||
_handleDocumentModified(data);
|
||
break;
|
||
|
||
/// 🔹 Directory / Contacts
|
||
case 'Contact_Modified':
|
||
_handleContactModified(data);
|
||
break;
|
||
|
||
case 'Contact_Note_Modified':
|
||
_handleContactNoteModified(data);
|
||
break;
|
||
|
||
case 'Bucket_Modified':
|
||
_handleBucketModified(data);
|
||
break;
|
||
|
||
case 'Bucket_Assigned':
|
||
_handleBucketAssigned(data);
|
||
break;
|
||
|
||
default:
|
||
_logger.w('⚠️ Unhandled notification keyword: $keyword');
|
||
}
|
||
}
|
||
|
||
/// ---------------------- HANDLERS ----------------------
|
||
|
||
static void _handleTaskPlanningUpdated(Map<String, dynamic> data) {
|
||
final projectId = data['ProjectId'];
|
||
if (projectId == null) {
|
||
_logger.w("⚠️ TaskPlanning update received without ProjectId: $data");
|
||
return;
|
||
}
|
||
|
||
_safeControllerUpdate<DailyTaskPlanningController>(
|
||
onFound: (controller) {
|
||
controller.fetchTaskData(projectId);
|
||
},
|
||
notFoundMessage:
|
||
'⚠️ DailyTaskPlanningController not found, cannot refresh.',
|
||
successMessage:
|
||
'✅ DailyTaskPlanningController refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
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<String, dynamic> data) {
|
||
final expenseId = data['ExpenseId'];
|
||
if (expenseId == null) {
|
||
_logger.w("⚠️ Expense update received without ExpenseId: $data");
|
||
return;
|
||
}
|
||
|
||
// Update Expense List
|
||
_safeControllerUpdate<ExpenseController>(
|
||
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<ExpenseDetailController>(
|
||
onFound: (controller) async {
|
||
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<String, dynamic> data) {
|
||
_safeControllerUpdate<AttendanceController>(
|
||
onFound: (controller) => controller.refreshDataFromNotification(
|
||
projectId: data['ProjectId'],
|
||
),
|
||
notFoundMessage: '⚠️ AttendanceController not found, cannot update.',
|
||
successMessage: '✅ AttendanceController refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
static void _handleTaskUpdated(Map<String, dynamic> data,
|
||
{required bool isComment}) {
|
||
_safeControllerUpdate<DailyTaskController>(
|
||
onFound: (controller) => controller.refreshTasksFromNotification(
|
||
projectId: data['ProjectId'],
|
||
taskAllocationId: data['TaskAllocationId'],
|
||
),
|
||
notFoundMessage: '⚠️ DailyTaskController not found, cannot update.',
|
||
successMessage: '✅ DailyTaskController refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
/// ---------------------- DOCUMENT HANDLER ----------------------
|
||
static void _handleDocumentModified(Map<String, dynamic> data) {
|
||
final entityTypeId = data['EntityTypeId'];
|
||
final entityId = data['EntityId'];
|
||
|
||
if (entityTypeId == null || entityId == null) {
|
||
_logger.w(
|
||
"⚠️ Document update received without EntityTypeId/EntityId: $data");
|
||
return;
|
||
}
|
||
|
||
// Refresh document list
|
||
_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 open and matches)
|
||
// Refresh document details (if open and matches)
|
||
final documentId = data['DocumentId'];
|
||
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 ----------------------
|
||
|
||
static void _handleContactModified(Map<String, dynamic> data) {
|
||
_safeControllerUpdate<DirectoryController>(
|
||
onFound: (controller) => controller.fetchContacts(),
|
||
notFoundMessage: '⚠️ DirectoryController not found, cannot refresh.',
|
||
successMessage: '✅ Directory contacts refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
static void _handleContactNoteModified(Map<String, dynamic> data) {
|
||
final contactId = data['contactId'];
|
||
|
||
_safeControllerUpdate<DirectoryController>(
|
||
onFound: (controller) {
|
||
if (contactId != null) {
|
||
controller.fetchCommentsForContact(contactId);
|
||
}
|
||
},
|
||
notFoundMessage:
|
||
'⚠️ DirectoryController not found, cannot refresh notes.',
|
||
successMessage: '✅ Directory comments refreshed from notification.',
|
||
);
|
||
|
||
_safeControllerUpdate<NotesController>(
|
||
onFound: (controller) => controller.fetchNotes(),
|
||
notFoundMessage: '⚠️ NotesController not found, cannot refresh.',
|
||
successMessage: '✅ Notes refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
static void _handleBucketModified(Map<String, dynamic> data) {
|
||
_safeControllerUpdate<DirectoryController>(
|
||
onFound: (controller) => controller.fetchBuckets(),
|
||
notFoundMessage: '⚠️ DirectoryController not found, cannot refresh.',
|
||
successMessage: '✅ Buckets refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
static void _handleBucketAssigned(Map<String, dynamic> data) {
|
||
_safeControllerUpdate<DirectoryController>(
|
||
onFound: (controller) => controller.fetchBuckets(),
|
||
notFoundMessage: '⚠️ DirectoryController not found, cannot refresh.',
|
||
successMessage: '✅ Bucket assignments refreshed from notification.',
|
||
);
|
||
}
|
||
|
||
/// ---------------------- UTILITY ----------------------
|
||
|
||
static void _safeControllerUpdate<T>({
|
||
required void Function(T controller) onFound,
|
||
required String notFoundMessage,
|
||
required String successMessage,
|
||
}) {
|
||
try {
|
||
final controller = Get.find<T>();
|
||
onFound(controller);
|
||
_logger.i(successMessage);
|
||
} catch (e) {
|
||
_logger.w(notFoundMessage);
|
||
}
|
||
}
|
||
}
|