feat: Enhance organization selection and fetching logic with reactive state management
This commit is contained in:
parent
1d9c416f68
commit
85d3dedbef
@ -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<Organization> organizations = [];
|
||||
Organization? selectedOrganization;
|
||||
|
||||
/// Currently selected organization (reactive)
|
||||
Rxn<Organization> selectedOrganization = Rxn<Organization>();
|
||||
|
||||
/// Loading state for fetching organizations
|
||||
final isLoadingOrganizations = false.obs;
|
||||
|
||||
/// Fetch organizations assigned to a given project
|
||||
Future<void> 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";
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ class OrganizationSelector extends StatelessWidget {
|
||||
required List<String> items,
|
||||
}) {
|
||||
return PopupMenuButton<String>(
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
),
|
||||
|
@ -48,7 +48,7 @@ class _EmployeesScreenState extends State<EmployeesScreen> with UIMixin {
|
||||
|
||||
Future<void> _initEmployees() async {
|
||||
final projectId = Get.find<ProjectController>().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<EmployeesScreen> with UIMixin {
|
||||
Future<void> _refreshEmployees() async {
|
||||
try {
|
||||
final projectId = Get.find<ProjectController>().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<EmployeesScreen> with UIMixin {
|
||||
controller: _organizationController,
|
||||
height: 36,
|
||||
onSelectionChanged: (org) async {
|
||||
// Make sure the selectedOrganization is updated immediately
|
||||
_organizationController.selectOrganization(org);
|
||||
|
||||
final projectId =
|
||||
Get.find<ProjectController>().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']);
|
||||
},
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user