feat: Improve dynamic menu fetching with enhanced error handling and cache fallback

This commit is contained in:
Vaibhav Surve 2025-09-09 10:47:22 +05:30
parent 99bd26942c
commit a02887845b

View File

@ -13,19 +13,29 @@ class DynamicMenuController extends GetxController {
final RxList<MenuItem> menuItems = <MenuItem>[].obs;
Timer? _autoRefreshTimer;
@override
void onInit() {
super.onInit();
// Load cached menus immediately (so user doesnt see empty state)
final cachedMenus = LocalStorage.getMenus();
if (cachedMenus.isNotEmpty) {
menuItems.assignAll(cachedMenus);
logSafe("Loaded ${cachedMenus.length} menus from cache at startup");
}
// Fetch from API in background
fetchMenu();
/// Auto refresh every 5 minutes (adjust as needed)
// Auto refresh every 15 minutes
_autoRefreshTimer = Timer.periodic(
const Duration(minutes: 15),
(_) => fetchMenu(),
);
}
/// Fetch dynamic menu from API with error and local storage support
/// Fetch dynamic menu from API with cache fallback
Future<void> fetchMenu() async {
isLoading.value = true;
hasError.value = false;
@ -34,45 +44,39 @@ class DynamicMenuController extends GetxController {
try {
final responseData = await ApiService.getMenuApi();
if (responseData != null) {
// Directly parse full JSON into MenuResponse
// Parse JSON into MenuResponse
final menuResponse = MenuResponse.fromJson(responseData);
menuItems.assignAll(menuResponse.data);
// Save menus for offline use
// Save for offline use
await LocalStorage.setMenus(menuItems);
logSafe("Menu loaded from API with ${menuItems.length} items");
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();
}
_handleApiFailure("Menu API returned null response");
}
} 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();
}
_handleApiFailure("Menu fetch exception: $e");
} finally {
isLoading.value = false;
}
}
void _handleApiFailure(String logMessage) {
logSafe(logMessage, level: LogLevel.error);
final cachedMenus = LocalStorage.getMenus();
if (cachedMenus.isNotEmpty) {
menuItems.assignAll(cachedMenus);
errorMessage.value = "⚠️ Using offline menus (latest sync failed)";
logSafe("Loaded ${menuItems.length} menus from cache after failure");
} else {
hasError.value = true;
errorMessage.value = "❌ Unable to load menus. Please try again later.";
menuItems.clear();
}
}
bool isMenuAllowed(String menuName) {
final menu = menuItems.firstWhereOrNull((m) => m.name == menuName);
return menu?.available ?? false; // default false if not found
@ -80,7 +84,7 @@ class DynamicMenuController extends GetxController {
@override
void onClose() {
_autoRefreshTimer?.cancel(); // clean up timer
_autoRefreshTimer?.cancel();
super.onClose();
}
}