diff --git a/lib/controller/tenant/organization_selection_controller.dart b/lib/controller/tenant/organization_selection_controller.dart index 5b189d6..ee6db6e 100644 --- a/lib/controller/tenant/organization_selection_controller.dart +++ b/lib/controller/tenant/organization_selection_controller.dart @@ -4,37 +4,49 @@ import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/attendance/organization_per_project_list_model.dart'; class OrganizationController extends GetxController { + /// List of organizations assigned to the selected project List organizations = []; - Organization? selectedOrganization; + + /// Currently selected organization (reactive) + Rxn selectedOrganization = Rxn(); + + /// Loading state for fetching organizations final isLoadingOrganizations = false.obs; + /// Fetch organizations assigned to a given project Future fetchOrganizations(String projectId) async { try { isLoadingOrganizations.value = true; + final response = await ApiService.getAssignedOrganizations(projectId); - if (response != null) { + if (response != null && response.data.isNotEmpty) { organizations = response.data; logSafe("Organizations fetched: ${organizations.length}"); } else { - logSafe("Failed to fetch organizations for project $projectId", - level: LogLevel.error); + organizations = []; + logSafe("No organizations found for project $projectId", + level: LogLevel.warning); } + } catch (e, stackTrace) { + logSafe("Failed to fetch organizations: $e", + level: LogLevel.error, error: e, stackTrace: stackTrace); + organizations = []; } finally { isLoadingOrganizations.value = false; - update(); } } + /// Select an organization void selectOrganization(Organization? org) { - selectedOrganization = org; - update(); + selectedOrganization.value = org; } + /// Clear the selection (set to "All Organizations") void clearSelection() { - selectedOrganization = null; - update(); + selectedOrganization.value = null; } + /// Current selection name for UI String get currentSelection => - selectedOrganization?.name ?? "All Organizations"; + selectedOrganization.value?.name ?? "All Organizations"; } diff --git a/lib/helpers/utils/attendance_actions.dart b/lib/helpers/utils/attendance_actions.dart index 927d02c..cc67376 100644 --- a/lib/helpers/utils/attendance_actions.dart +++ b/lib/helpers/utils/attendance_actions.dart @@ -24,8 +24,8 @@ class AttendanceActionColors { ButtonActions.rejected: Colors.orange, ButtonActions.approved: Colors.green, ButtonActions.requested: Colors.yellow, - ButtonActions.approve: Colors.blueAccent, - ButtonActions.reject: Colors.pink, + ButtonActions.approve: Colors.green, + ButtonActions.reject: Colors.red, }; } diff --git a/lib/helpers/widgets/tenant/organization_selector.dart b/lib/helpers/widgets/tenant/organization_selector.dart index c35afa8..8295f97 100644 --- a/lib/helpers/widgets/tenant/organization_selector.dart +++ b/lib/helpers/widgets/tenant/organization_selector.dart @@ -25,7 +25,7 @@ class OrganizationSelector extends StatelessWidget { required List items, }) { return PopupMenuButton( - color: Colors.white, + color: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), onSelected: (name) async { Organization? org = name == "All Organizations" @@ -45,8 +45,7 @@ class OrganizationSelector extends StatelessWidget { height: height, padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( - color: - Colors.white, + color: Colors.white, border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(12), ), @@ -97,6 +96,7 @@ class OrganizationSelector extends StatelessWidget { ...controller.organizations.map((e) => e.name) ]; + // Listen to selectedOrganization.value return _popupSelector( currentValue: controller.currentSelection, items: orgNames, diff --git a/lib/model/attendance/attendence_filter_sheet.dart b/lib/model/attendance/attendence_filter_sheet.dart index e7983e7..f9b2467 100644 --- a/lib/model/attendance/attendence_filter_sheet.dart +++ b/lib/model/attendance/attendence_filter_sheet.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:marco/controller/permission_controller.dart'; import 'package:marco/controller/attendance/attendance_screen_controller.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/utils/permission_constants.dart'; import 'package:marco/helpers/utils/base_bottom_sheet.dart'; import 'package:get/get.dart'; +import 'package:marco/helpers/utils/date_time_utils.dart'; class AttendanceFilterBottomSheet extends StatefulWidget { final AttendanceController controller; @@ -37,9 +37,11 @@ class _AttendanceFilterBottomSheetState String getLabelText() { final startDate = widget.controller.startDateAttendance; final endDate = widget.controller.endDateAttendance; + if (startDate != null && endDate != null) { - final start = DateFormat('dd/MM/yyyy').format(startDate); - final end = DateFormat('dd/MM/yyyy').format(endDate); + final start = + DateTimeUtils.formatDate(startDate, 'dd MMM yyyy'); + final end = DateTimeUtils.formatDate(endDate, 'dd MMM yyyy'); return "$start - $end"; } return "Date Range"; @@ -96,7 +98,7 @@ class _AttendanceFilterBottomSheetState onSelected: (name) { if (name == "All Organizations") { setState(() { - widget.controller.selectedOrganization = null; + widget.controller.selectedOrganization = null; }); } else { final selectedOrg = widget.controller.organizations @@ -154,7 +156,7 @@ class _AttendanceFilterBottomSheetState padding: const EdgeInsets.only(top: 12, bottom: 12), child: Align( alignment: Alignment.centerLeft, - child: MyText.titleSmall("Select Organization", fontWeight: 600), + child: MyText.titleSmall("Choose Organization", fontWeight: 600), ), ), Obx(() { @@ -231,7 +233,7 @@ class _AttendanceFilterBottomSheetState borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), child: BaseBottomSheet( title: "Attendance Filter", - submitText: "Apply", + submitText: "Apply", onCancel: () => Navigator.pop(context), onSubmit: () => Navigator.pop(context, { 'selectedTab': tempSelectedTab, diff --git a/lib/model/attendance/log_details_view.dart b/lib/model/attendance/log_details_view.dart index b2ad720..79f57b4 100644 --- a/lib/model/attendance/log_details_view.dart +++ b/lib/model/attendance/log_details_view.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:marco/helpers/widgets/my_text.dart'; -import 'package:marco/helpers/utils/attendance_actions.dart'; import 'package:marco/helpers/utils/base_bottom_sheet.dart'; class AttendanceLogViewButton extends StatelessWidget { @@ -219,7 +218,7 @@ class AttendanceLogViewButton extends StatelessWidget { child: ElevatedButton( onPressed: () => _showLogsBottomSheet(context), style: ElevatedButton.styleFrom( - backgroundColor: AttendanceActionColors.colors[ButtonActions.checkIn], + backgroundColor: Colors.indigo, textStyle: const TextStyle(fontSize: 12), padding: const EdgeInsets.symmetric(horizontal: 12), ), diff --git a/lib/view/employees/employees_screen.dart b/lib/view/employees/employees_screen.dart index 6b6435e..7d015ce 100644 --- a/lib/view/employees/employees_screen.dart +++ b/lib/view/employees/employees_screen.dart @@ -48,7 +48,7 @@ class _EmployeesScreenState extends State with UIMixin { Future _initEmployees() async { final projectId = Get.find().selectedProject?.id; - final orgId = _organizationController.selectedOrganization?.id; + final orgId = _organizationController.selectedOrganization.value?.id; if (projectId != null) { await _organizationController.fetchOrganizations(projectId); @@ -71,7 +71,7 @@ class _EmployeesScreenState extends State with UIMixin { Future _refreshEmployees() async { try { final projectId = Get.find().selectedProject?.id; - final orgId = _organizationController.selectedOrganization?.id; + final orgId = _organizationController.selectedOrganization.value?.id; final allSelected = _employeeController.isAllEmployeeSelected.value; _employeeController.selectedProjectId = allSelected ? null : projectId; @@ -300,17 +300,23 @@ class _EmployeesScreenState extends State with UIMixin { controller: _organizationController, height: 36, onSelectionChanged: (org) async { + // Make sure the selectedOrganization is updated immediately + _organizationController.selectOrganization(org); + final projectId = Get.find().selectedProject?.id; if (_employeeController.isAllEmployeeSelected.value) { await _employeeController.fetchAllEmployees( - organizationId: org?.id); + organizationId: _organizationController + .selectedOrganization.value?.id); } else if (projectId != null) { await _employeeController.fetchEmployeesByProject( projectId, - organizationId: org?.id); + organizationId: _organizationController + .selectedOrganization.value?.id); } + _employeeController.update(['employee_screen_controller']); }, ),