marco.pms.mobileapp/lib/controller/dynamicMenu/dynamic_menu_controller.dart
Vaibhav Surve f5d4ab8415 feat: Add attendance log screen and related functionalities
- Implemented AttendenceLogScreen to display employee attendance logs.
- Created RegularizationRequestsTab to manage regularization requests.
- Added TodaysAttendanceTab for viewing today's attendance.
- Removed outdated dashboard chart implementation.
- Updated dashboard screen to integrate new attendance overview and project progress charts.
- Refactored employee detail and employee screens to use updated controllers.
- Organized expense-related imports and components for better structure.
- Adjusted daily progress report to use the correct controller.
2025-08-29 15:53:19 +05:30

87 lines
2.6 KiB
Dart

import 'dart:async';
import 'package:get/get.dart';
import 'package:marco/model/dynamicMenu/dynamic_menu_model.dart';
import 'package:marco/helpers/services/api_service.dart';
import 'package:marco/helpers/services/app_logger.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
class DynamicMenuController extends GetxController {
// UI reactive states
final RxBool isLoading = false.obs;
final RxBool hasError = false.obs;
final RxString errorMessage = ''.obs;
final RxList<MenuItem> menuItems = <MenuItem>[].obs;
Timer? _autoRefreshTimer;
@override
void onInit() {
super.onInit();
fetchMenu();
/// Auto refresh every 5 minutes (adjust as needed)
_autoRefreshTimer = Timer.periodic(
const Duration(minutes: 15),
(_) => fetchMenu(),
);
}
/// Fetch dynamic menu from API with error and local storage support
Future<void> fetchMenu() async {
isLoading.value = true;
hasError.value = false;
errorMessage.value = '';
try {
final responseData = await ApiService.getMenuApi();
if (responseData != null) {
// Directly parse full JSON into MenuResponse
final menuResponse = MenuResponse.fromJson(responseData);
menuItems.assignAll(menuResponse.data);
// Save menus for offline use
await LocalStorage.setMenus(menuItems);
logSafe("Menu loaded from API with ${menuItems.length} items");
} else {
// If API fails, load from cache
final cachedMenus = LocalStorage.getMenus();
if (cachedMenus.isNotEmpty) {
menuItems.assignAll(cachedMenus);
logSafe("Loaded menus from cache: ${menuItems.length} items");
} else {
hasError.value = true;
errorMessage.value = "Failed to fetch menu";
menuItems.clear();
}
}
} catch (e) {
logSafe("Menu fetch exception: $e", level: LogLevel.error);
// On error, load cached menus
final cachedMenus = LocalStorage.getMenus();
if (cachedMenus.isNotEmpty) {
menuItems.assignAll(cachedMenus);
logSafe("Loaded menus from cache after error: ${menuItems.length}");
} else {
hasError.value = true;
errorMessage.value = e.toString();
menuItems.clear();
}
} finally {
isLoading.value = false;
}
}
bool isMenuAllowed(String menuName) {
final menu = menuItems.firstWhereOrNull((m) => m.name == menuName);
return menu?.available ?? false; // default false if not found
}
@override
void onClose() {
_autoRefreshTimer?.cancel(); // clean up timer
super.onClose();
}
}