marco.pms.mobileapp/lib/helpers/services/notification_action_handler.dart
Vaibhav Surve 311002f3ba Refactor expense deletion confirmation dialog and add validation to add expense form
- Replaced the custom delete confirmation dialog with a reusable ConfirmDialog widget for better code organization and reusability.
- Improved the add expense bottom sheet by implementing form validation using a GlobalKey and TextFormField.
- Enhanced user experience by adding validation for required fields and specific formats (e.g., GST, transaction ID).
- Updated the expense list to reflect changes in the confirmation dialog and improved the handling of attachments.
- Cleaned up code by removing unnecessary comments and ensuring consistent formatting.
2025-08-26 11:09:50 +05:30

184 lines
5.8 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<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':
// 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<String, dynamic> 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<String, dynamic> data) {
final projectId = data['ProjectId'];
if (projectId == null) {
_logger.w("⚠️ TaskPlanning update received without ProjectId: $data");
return;
}
_safeControllerUpdate<DailyTaskPlaningController>(
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<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 {
// 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<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.',
);
}
/// Generic reusable method for safe GetX controller access + log handling
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);
}
}
}