import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import '../../domain/provider/product/all_products.dart'; import '../../modules/product/product.dart'; class ProductsController extends GetxController { final ProductsProvider provider = ProductsProvider(); var isConnected = true.obs; var isLoading = false.obs; var productResponse = Rxn(); var selectedIndex = 0.obs; var searchQuery = ''.obs; var isSearching = false.obs; /// In-memory cache: key is "categoryId_tenantId" final Map _cache = {}; @override void onInit() { super.onInit(); // Listen for connectivity changes Connectivity().onConnectivityChanged.listen((status) { isConnected.value = (status != ConnectivityResult.none); }); } Future hasInternet() async { try { final response = await http.get(Uri.parse('https://www.google.com')) .timeout(const Duration(seconds: 5)); if (response.statusCode == 200) { return true; } return false; } catch (e) { return false; } } Future fetchProducts(int categoryId, int tenantId, int locationId) async { final cacheKey = '${categoryId}_${tenantId}_$locationId'; // ✅ Include locationId in cache key // 1️⃣ Use cache if available if (_cache.containsKey(cacheKey)) { productResponse.value = _cache[cacheKey]; return; } isLoading.value = true; bool connected = await hasInternet(); if (!connected) { isLoading.value = false; isConnected = false.obs; return; // Stop fetching } // 2️⃣ Otherwise fetch from API try { isLoading.value = true; final response = await provider.getProductsBySubCategory( categoryId: categoryId, tenantId: tenantId, locationId: locationId, // ✅ Pass locationId to API ); productResponse.value = response; // 3️⃣ Save in cache _cache[cacheKey] = response!; } finally { isLoading.value = false; } } /// Force refresh API and update cache Future refreshProducts(int categoryId, int tenantId, int locationId) async { final cacheKey = '${categoryId}_${tenantId}_$locationId'; // ✅ Include locationId try { isLoading.value = true; final response = await provider.getProductsBySubCategory( categoryId: categoryId, tenantId: tenantId, locationId: locationId, // ✅ Pass locationId to API ); productResponse.value = response; // ✅ Update cache with new key _cache[cacheKey] = response!; } finally { isLoading.value = false; } } /// Returns products depending on search query and selected subcategory List get filteredProducts { // Check if nested data exists (main API) final details = productResponse.value?.data?.details; if (details != null && details.isNotEmpty) { if (searchQuery.value.isEmpty) { final selectedDetail = details[selectedIndex.value]; return selectedDetail.products ?? []; } List allProducts = []; for (var detail in details) { allProducts.addAll(detail.products ?? []); } return allProducts .where((p) => (p.productname ?? '') .toLowerCase() .contains(searchQuery.value.toLowerCase())) .toList(); } // If flat details exist (variants API) final variantDetails = productResponse.value?.details ?? []; if (variantDetails.isNotEmpty) { if (searchQuery.value.isEmpty) return variantDetails; return variantDetails .where((p) => (p.productname ?? '') .toLowerCase() .contains(searchQuery.value.toLowerCase())) .toList(); } return []; } // NEW: Dedicated method for subcategory-specific screen List getProductsBySubcategory(String subCategoryName) { final details = productResponse.value?.data?.details ?? []; if (details.isEmpty) { return []; } // Find matching subcategory (case-insensitive, trimmed for safety) final matchingDetail = details.firstWhere( (detail) => (detail.subcategoryname ?? '').trim().toLowerCase() == subCategoryName.trim().toLowerCase(), orElse: () => Detail(), // fallback - make sure Detail() is valid in your modules ); // Return the products of that subcategory (or empty if no match) return matchingDetail.products ?? []; } }