Files
2026-05-26 18:01:57 +05:30

163 lines
4.6 KiB
Dart
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<ProductResponse>();
var selectedIndex = 0.obs;
var searchQuery = ''.obs;
var isSearching = false.obs;
/// In-memory cache: key is "categoryId_tenantId"
final Map<String, ProductResponse> _cache = {};
@override
void onInit() {
super.onInit();
// Listen for connectivity changes
Connectivity().onConnectivityChanged.listen((status) {
isConnected.value = (status != ConnectivityResult.none);
});
}
Future<bool> 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<void> 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<void> 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<Product> 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<Product> 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<Product> 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 ?? [];
}
}