feat: Improve dynamic menu fetching with enhanced error handling and cache fallback
This commit is contained in:
parent
99bd26942c
commit
a02887845b
@ -13,19 +13,29 @@ class DynamicMenuController extends GetxController {
|
|||||||
final RxList<MenuItem> menuItems = <MenuItem>[].obs;
|
final RxList<MenuItem> menuItems = <MenuItem>[].obs;
|
||||||
|
|
||||||
Timer? _autoRefreshTimer;
|
Timer? _autoRefreshTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
|
||||||
|
// ✅ Load cached menus immediately (so user doesn’t 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();
|
fetchMenu();
|
||||||
|
|
||||||
/// Auto refresh every 5 minutes (adjust as needed)
|
// Auto refresh every 15 minutes
|
||||||
_autoRefreshTimer = Timer.periodic(
|
_autoRefreshTimer = Timer.periodic(
|
||||||
const Duration(minutes: 15),
|
const Duration(minutes: 15),
|
||||||
(_) => fetchMenu(),
|
(_) => fetchMenu(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch dynamic menu from API with error and local storage support
|
/// Fetch dynamic menu from API with cache fallback
|
||||||
Future<void> fetchMenu() async {
|
Future<void> fetchMenu() async {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
hasError.value = false;
|
hasError.value = false;
|
||||||
@ -34,45 +44,39 @@ class DynamicMenuController extends GetxController {
|
|||||||
try {
|
try {
|
||||||
final responseData = await ApiService.getMenuApi();
|
final responseData = await ApiService.getMenuApi();
|
||||||
if (responseData != null) {
|
if (responseData != null) {
|
||||||
// Directly parse full JSON into MenuResponse
|
// Parse JSON into MenuResponse
|
||||||
final menuResponse = MenuResponse.fromJson(responseData);
|
final menuResponse = MenuResponse.fromJson(responseData);
|
||||||
|
|
||||||
menuItems.assignAll(menuResponse.data);
|
menuItems.assignAll(menuResponse.data);
|
||||||
|
|
||||||
// Save menus for offline use
|
// Save for offline use
|
||||||
await LocalStorage.setMenus(menuItems);
|
await LocalStorage.setMenus(menuItems);
|
||||||
|
|
||||||
logSafe("Menu loaded from API with ${menuItems.length} items");
|
logSafe("✅ Menu loaded from API with ${menuItems.length} items");
|
||||||
} else {
|
} else {
|
||||||
// If API fails, load from cache
|
_handleApiFailure("Menu API returned null response");
|
||||||
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) {
|
} catch (e) {
|
||||||
logSafe("Menu fetch exception: $e", level: LogLevel.error);
|
_handleApiFailure("Menu fetch exception: $e");
|
||||||
|
|
||||||
// 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 {
|
} finally {
|
||||||
isLoading.value = false;
|
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) {
|
bool isMenuAllowed(String menuName) {
|
||||||
final menu = menuItems.firstWhereOrNull((m) => m.name == menuName);
|
final menu = menuItems.firstWhereOrNull((m) => m.name == menuName);
|
||||||
return menu?.available ?? false; // default false if not found
|
return menu?.available ?? false; // default false if not found
|
||||||
@ -80,7 +84,7 @@ class DynamicMenuController extends GetxController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
_autoRefreshTimer?.cancel(); // clean up timer
|
_autoRefreshTimer?.cancel();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user