refactor: Clean up attendance controller initialization and enhance project change handling
This commit is contained in:
parent
ebc8996f71
commit
c78c14e409
@ -51,11 +51,6 @@ class AttendanceController extends GetxController {
|
|||||||
super.onInit();
|
super.onInit();
|
||||||
_initializeDefaults();
|
_initializeDefaults();
|
||||||
|
|
||||||
// 🔹 Fetch organizations for the selected project
|
|
||||||
final projectId = Get.find<ProjectController>().selectedProject?.id;
|
|
||||||
if (projectId != null) {
|
|
||||||
fetchOrganizations(projectId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initializeDefaults() {
|
void _initializeDefaults() {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
class ApiEndpoints {
|
class ApiEndpoints {
|
||||||
static const String baseUrl = "https://stageapi.marcoaiot.com/api";
|
// static const String baseUrl = "https://stageapi.marcoaiot.com/api";
|
||||||
// static const String baseUrl = "https://api.marcoaiot.com/api";
|
static const String baseUrl = "https://api.marcoaiot.com/api";
|
||||||
// static const String baseUrl = "https://devapi.marcoaiot.com/api";
|
// static const String baseUrl = "https://devapi.marcoaiot.com/api";
|
||||||
|
|
||||||
// Dashboard Module API Endpoints
|
// Dashboard Module API Endpoints
|
||||||
|
|||||||
@ -69,7 +69,6 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Team_Modified':
|
case 'Team_Modified':
|
||||||
// Call method to handle team modifications and dashboard update
|
|
||||||
_handleDashboardUpdate(data);
|
_handleDashboardUpdate(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -129,6 +128,11 @@ class NotificationActionHandler {
|
|||||||
/// ---------------------- HANDLERS ----------------------
|
/// ---------------------- HANDLERS ----------------------
|
||||||
|
|
||||||
static void _handleTaskPlanningUpdated(Map<String, dynamic> data) {
|
static void _handleTaskPlanningUpdated(Map<String, dynamic> data) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored task planning update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final projectId = data['ProjectId'];
|
final projectId = data['ProjectId'];
|
||||||
if (projectId == null) {
|
if (projectId == null) {
|
||||||
_logger.w("⚠️ TaskPlanning update received without ProjectId: $data");
|
_logger.w("⚠️ TaskPlanning update received without ProjectId: $data");
|
||||||
@ -159,13 +163,17 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _handleExpenseUpdated(Map<String, dynamic> data) {
|
static void _handleExpenseUpdated(Map<String, dynamic> data) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored expense update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final expenseId = data['ExpenseId'];
|
final expenseId = data['ExpenseId'];
|
||||||
if (expenseId == null) {
|
if (expenseId == null) {
|
||||||
_logger.w("⚠️ Expense update received without ExpenseId: $data");
|
_logger.w("⚠️ Expense update received without ExpenseId: $data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Expense List
|
|
||||||
_safeControllerUpdate<ExpenseController>(
|
_safeControllerUpdate<ExpenseController>(
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
await controller.fetchExpenses();
|
await controller.fetchExpenses();
|
||||||
@ -175,7 +183,6 @@ class NotificationActionHandler {
|
|||||||
'✅ ExpenseController refreshed from expense notification.',
|
'✅ ExpenseController refreshed from expense notification.',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update Expense Detail (if open and matches this expenseId)
|
|
||||||
_safeControllerUpdate<ExpenseDetailController>(
|
_safeControllerUpdate<ExpenseDetailController>(
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
if (controller.expense.value?.id == expenseId) {
|
if (controller.expense.value?.id == expenseId) {
|
||||||
@ -190,6 +197,11 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _handleAttendanceUpdated(Map<String, dynamic> data) {
|
static void _handleAttendanceUpdated(Map<String, dynamic> data) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored attendance update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_safeControllerUpdate<AttendanceController>(
|
_safeControllerUpdate<AttendanceController>(
|
||||||
onFound: (controller) => controller.refreshDataFromNotification(
|
onFound: (controller) => controller.refreshDataFromNotification(
|
||||||
projectId: data['ProjectId'],
|
projectId: data['ProjectId'],
|
||||||
@ -201,6 +213,11 @@ class NotificationActionHandler {
|
|||||||
|
|
||||||
static void _handleTaskUpdated(Map<String, dynamic> data,
|
static void _handleTaskUpdated(Map<String, dynamic> data,
|
||||||
{required bool isComment}) {
|
{required bool isComment}) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored task update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_safeControllerUpdate<DailyTaskController>(
|
_safeControllerUpdate<DailyTaskController>(
|
||||||
onFound: (controller) => controller.refreshTasksFromNotification(
|
onFound: (controller) => controller.refreshTasksFromNotification(
|
||||||
projectId: data['ProjectId'],
|
projectId: data['ProjectId'],
|
||||||
@ -213,11 +230,15 @@ class NotificationActionHandler {
|
|||||||
|
|
||||||
/// ---------------------- DOCUMENT HANDLER ----------------------
|
/// ---------------------- DOCUMENT HANDLER ----------------------
|
||||||
static void _handleDocumentModified(Map<String, dynamic> data) {
|
static void _handleDocumentModified(Map<String, dynamic> data) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored document update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String entityTypeId;
|
String entityTypeId;
|
||||||
String entityId;
|
String entityId;
|
||||||
String? documentId = data['DocumentId'];
|
String? documentId = data['DocumentId'];
|
||||||
|
|
||||||
// Determine entity type and ID
|
|
||||||
if (data['Keyword'] == 'Employee_Document_Modified') {
|
if (data['Keyword'] == 'Employee_Document_Modified') {
|
||||||
entityTypeId = Permissions.employeeEntity;
|
entityTypeId = Permissions.employeeEntity;
|
||||||
entityId = data['EmployeeId'] ?? '';
|
entityId = data['EmployeeId'] ?? '';
|
||||||
@ -237,7 +258,6 @@ class NotificationActionHandler {
|
|||||||
_logger.i(
|
_logger.i(
|
||||||
"🔔 Document notification received: keyword=${data['Keyword']}, entityTypeId=$entityTypeId, entityId=$entityId, documentId=$documentId");
|
"🔔 Document notification received: keyword=${data['Keyword']}, entityTypeId=$entityTypeId, entityId=$entityId, documentId=$documentId");
|
||||||
|
|
||||||
// Refresh Document List
|
|
||||||
if (Get.isRegistered<DocumentController>()) {
|
if (Get.isRegistered<DocumentController>()) {
|
||||||
_safeControllerUpdate<DocumentController>(
|
_safeControllerUpdate<DocumentController>(
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
@ -255,11 +275,9 @@ class NotificationActionHandler {
|
|||||||
_logger.w('⚠️ DocumentController not registered, skipping list refresh.');
|
_logger.w('⚠️ DocumentController not registered, skipping list refresh.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh Document Details (if open)
|
|
||||||
if (documentId != null && Get.isRegistered<DocumentDetailsController>()) {
|
if (documentId != null && Get.isRegistered<DocumentDetailsController>()) {
|
||||||
_safeControllerUpdate<DocumentDetailsController>(
|
_safeControllerUpdate<DocumentDetailsController>(
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
// Refresh details regardless of current document
|
|
||||||
await controller.fetchDocumentDetails(documentId);
|
await controller.fetchDocumentDetails(documentId);
|
||||||
_logger.i(
|
_logger.i(
|
||||||
"✅ DocumentDetailsController refreshed for Document $documentId");
|
"✅ DocumentDetailsController refreshed for Document $documentId");
|
||||||
@ -276,13 +294,10 @@ class NotificationActionHandler {
|
|||||||
|
|
||||||
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
/// ---------------------- DIRECTORY HANDLERS ----------------------
|
||||||
static void _handleContactModified(Map<String, dynamic> data) {
|
static void _handleContactModified(Map<String, dynamic> data) {
|
||||||
final contactId = data['ContactId'];
|
|
||||||
|
|
||||||
// Always refresh the contact list
|
|
||||||
_safeControllerUpdate<DirectoryController>(
|
_safeControllerUpdate<DirectoryController>(
|
||||||
onFound: (controller) {
|
onFound: (controller) {
|
||||||
controller.fetchContacts();
|
controller.fetchContacts();
|
||||||
// If a specific contact is provided, refresh its notes as well
|
final contactId = data['ContactId'];
|
||||||
if (contactId != null) {
|
if (contactId != null) {
|
||||||
controller.fetchCommentsForContact(contactId);
|
controller.fetchCommentsForContact(contactId);
|
||||||
}
|
}
|
||||||
@ -293,7 +308,6 @@ class NotificationActionHandler {
|
|||||||
'✅ Directory contacts (and notes if applicable) refreshed from notification.',
|
'✅ Directory contacts (and notes if applicable) refreshed from notification.',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Refresh notes globally as well
|
|
||||||
_safeControllerUpdate<NotesController>(
|
_safeControllerUpdate<NotesController>(
|
||||||
onFound: (controller) => controller.fetchNotes(),
|
onFound: (controller) => controller.fetchNotes(),
|
||||||
notFoundMessage: '⚠️ NotesController not found, cannot refresh notes.',
|
notFoundMessage: '⚠️ NotesController not found, cannot refresh notes.',
|
||||||
@ -302,7 +316,6 @@ class NotificationActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _handleContactNoteModified(Map<String, dynamic> data) {
|
static void _handleContactNoteModified(Map<String, dynamic> data) {
|
||||||
// Refresh both contacts and notes when a note is modified
|
|
||||||
_handleContactModified(data);
|
_handleContactModified(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,6 +337,11 @@ class NotificationActionHandler {
|
|||||||
|
|
||||||
/// ---------------------- DASHBOARD HANDLER ----------------------
|
/// ---------------------- DASHBOARD HANDLER ----------------------
|
||||||
static void _handleDashboardUpdate(Map<String, dynamic> data) {
|
static void _handleDashboardUpdate(Map<String, dynamic> data) {
|
||||||
|
if (!_isCurrentProject(data)) {
|
||||||
|
_logger.i("ℹ️ Ignored dashboard update from another project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_safeControllerUpdate<DashboardController>(
|
_safeControllerUpdate<DashboardController>(
|
||||||
onFound: (controller) async {
|
onFound: (controller) async {
|
||||||
final type = data['type'] ?? '';
|
final type = data['type'] ?? '';
|
||||||
@ -347,11 +365,9 @@ class NotificationActionHandler {
|
|||||||
controller.projectController.selectedProjectId.value;
|
controller.projectController.selectedProjectId.value;
|
||||||
final projectIdsString = data['ProjectIds'] ?? '';
|
final projectIdsString = data['ProjectIds'] ?? '';
|
||||||
|
|
||||||
// Convert comma-separated string to List<String>
|
|
||||||
final notificationProjectIds =
|
final notificationProjectIds =
|
||||||
projectIdsString.split(',').map((e) => e.trim()).toList();
|
projectIdsString.split(',').map((e) => e.trim()).toList();
|
||||||
|
|
||||||
// Refresh only if current project ID is in the list
|
|
||||||
if (notificationProjectIds.contains(currentProjectId)) {
|
if (notificationProjectIds.contains(currentProjectId)) {
|
||||||
await controller.fetchDashboardTeams(projectId: currentProjectId);
|
await controller.fetchDashboardTeams(projectId: currentProjectId);
|
||||||
}
|
}
|
||||||
@ -375,6 +391,24 @@ class NotificationActionHandler {
|
|||||||
|
|
||||||
/// ---------------------- UTILITY ----------------------
|
/// ---------------------- UTILITY ----------------------
|
||||||
|
|
||||||
|
static bool _isCurrentProject(Map<String, dynamic> data) {
|
||||||
|
try {
|
||||||
|
final dashboard = Get.find<DashboardController>();
|
||||||
|
final currentProjectId =
|
||||||
|
dashboard.projectController.selectedProjectId.value;
|
||||||
|
final notificationProjectId = data['ProjectId']?.toString();
|
||||||
|
|
||||||
|
if (notificationProjectId == null || notificationProjectId.isEmpty) {
|
||||||
|
return true; // No project info → allow global refresh
|
||||||
|
}
|
||||||
|
|
||||||
|
return notificationProjectId == currentProjectId;
|
||||||
|
} catch (e) {
|
||||||
|
_logger.w("⚠️ Could not verify project context: $e");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _safeControllerUpdate<T>({
|
static void _safeControllerUpdate<T>({
|
||||||
required void Function(T controller) onFound,
|
required void Function(T controller) onFound,
|
||||||
required String notFoundMessage,
|
required String notFoundMessage,
|
||||||
|
|||||||
@ -34,12 +34,12 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
// Listen for future project selection changes
|
// 🔁 Listen for project changes
|
||||||
ever<String>(projectController.selectedProjectId, (projectId) async {
|
ever<String>(projectController.selectedProjectId, (projectId) async {
|
||||||
if (projectId.isNotEmpty) await _loadData(projectId);
|
if (projectId.isNotEmpty) await _loadData(projectId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load initial data
|
// 🚀 Load initial data only once the screen is shown
|
||||||
final projectId = projectController.selectedProjectId.value;
|
final projectId = projectController.selectedProjectId.value;
|
||||||
if (projectId.isNotEmpty) _loadData(projectId);
|
if (projectId.isNotEmpty) _loadData(projectId);
|
||||||
});
|
});
|
||||||
@ -47,7 +47,7 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
|||||||
|
|
||||||
Future<void> _loadData(String projectId) async {
|
Future<void> _loadData(String projectId) async {
|
||||||
try {
|
try {
|
||||||
attendanceController.selectedTab = 'todaysAttendance';
|
attendanceController.selectedTab = 'todaysAttendance';
|
||||||
await attendanceController.loadAttendanceData(projectId);
|
await attendanceController.loadAttendanceData(projectId);
|
||||||
attendanceController.update(['attendance_dashboard_controller']);
|
attendanceController.update(['attendance_dashboard_controller']);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -402,4 +402,13 @@ class _AttendanceScreenState extends State<AttendanceScreen> with UIMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// 🧹 Clean up the controller when user leaves this screen
|
||||||
|
if (Get.isRegistered<AttendanceController>()) {
|
||||||
|
Get.delete<AttendanceController>();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user