import 'package:flutter/material.dart'; import 'package:qpay/http/http.dart'; import 'package:qpay/models/api_response.dart'; import 'package:qpay/screens/home/home_controller.dart' as hc; import 'package:qpay/screens/pay/pay_controller.dart' as pc; // Provide access to the shared types from one place. typedef BillProvider = hc.BillProvider; typedef BillProduct = pc.BillProduct; typedef PaymentProcessor = pc.PaymentProcessor; class ProviderScreenModel { List providers = []; List products = []; List processors = []; BillProvider? selectedProvider; BillProduct? selectedProduct; PaymentProcessor? selectedProcessor; bool isLoadingProviders = false; bool isLoadingProducts = false; bool isLoadingProcessors = false; String? errorMessage; } class ProviderController extends ChangeNotifier { final ProviderScreenModel model = ProviderScreenModel(); final Http http = Http(); BuildContext context; bool _disposed = false; ProviderController(this.context); @override void dispose() { _disposed = true; super.dispose(); } dynamic _unwrap(dynamic response) { if (response is Map && response.containsKey('body')) { return response['body']; } return response; } // ── Providers ────────────────────────────────────────────── Future>> loadProviders(String currency) async { model.isLoadingProviders = true; model.errorMessage = null; model.providers = []; model.selectedProvider = null; model.products = []; model.selectedProduct = null; if (!_disposed) notifyListeners(); try { final raw = await http.get( '/public/providers?currency=$currency&sort=priority,asc', ); final response = _unwrap(raw); final List content; if (response is Map && response.containsKey('content')) { content = response['content'] as List; } else if (response is List) { content = response; } else { content = []; } model.providers = content .map((e) => BillProvider.fromJson(e as Map)) .toList(); model.isLoadingProviders = false; if (model.providers.isNotEmpty) { // Use selectProvider to also reset products and load matching products selectProvider(model.providers.first); } else { if (!_disposed) notifyListeners(); } return ApiResponse.success(model.providers); } catch (e) { logger.e(e); model.errorMessage = e.toString(); model.providers = []; model.selectedProvider = null; model.isLoadingProviders = false; if (!_disposed) notifyListeners(); return ApiResponse.failure( "Problem fetching providers, are you connected to the internet?", ); } } void selectProvider(BillProvider provider) { model.selectedProvider = provider; model.selectedProduct = null; model.products = []; if (!_disposed) notifyListeners(); // Automatically load products for the selected provider loadProducts(provider.id); } // ── Products ─────────────────────────────────────────────── Future>> loadProducts(String providerId) async { model.isLoadingProducts = true; model.errorMessage = null; model.selectedProduct = null; model.products = []; if (!_disposed) notifyListeners(); try { final raw = await http.get('/public/providers/$providerId/products'); final response = _unwrap(raw); final List list = response is List ? response : (response['content'] ?? []); model.products = list .map((e) => BillProduct.fromJson(e as Map)) .toList(); model.selectedProduct = model.products.isNotEmpty ? model.products.first : null; model.isLoadingProducts = false; if (!_disposed) notifyListeners(); return ApiResponse.success(model.products); } catch (e) { logger.e(e); model.errorMessage = e.toString(); model.products = []; model.selectedProduct = null; model.isLoadingProducts = false; if (!_disposed) notifyListeners(); return ApiResponse.failure( "Problem fetching products, are you connected to the internet?", ); } } void selectProduct(BillProduct product) { model.selectedProduct = product; if (!_disposed) notifyListeners(); } // ── Payment Processors ───────────────────────────────────── Future>> loadProcessors() async { model.isLoadingProcessors = true; model.errorMessage = null; if (!_disposed) notifyListeners(); try { final raw = await http.get('/public/payment-processors'); final response = _unwrap(raw); final List list = response is List ? response : (response['content'] ?? []); model.processors = list .map((e) => PaymentProcessor.fromJson(e as Map)) .toList(); if (model.processors.isNotEmpty && model.selectedProcessor == null) { model.selectedProcessor = model.processors.first; } model.isLoadingProcessors = false; if (!_disposed) notifyListeners(); return ApiResponse.success(model.processors); } catch (e) { logger.e(e); model.errorMessage = e.toString(); model.isLoadingProcessors = false; if (!_disposed) notifyListeners(); return ApiResponse.failure( "Problem fetching payment processors, are you connected to the internet?", ); } } void selectProcessor(PaymentProcessor processor) { model.selectedProcessor = processor; if (!_disposed) notifyListeners(); } }