completed batch feature
This commit is contained in:
182
lib/screens/provider/provider_controller.dart
Normal file
182
lib/screens/provider/provider_controller.dart
Normal file
@@ -0,0 +1,182 @@
|
||||
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<BillProvider> providers = [];
|
||||
List<BillProduct> products = [];
|
||||
List<PaymentProcessor> 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<ApiResponse<List<BillProvider>>> 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<dynamic> content;
|
||||
if (response is Map && response.containsKey('content')) {
|
||||
content = response['content'] as List<dynamic>;
|
||||
} else if (response is List) {
|
||||
content = response;
|
||||
} else {
|
||||
content = [];
|
||||
}
|
||||
model.providers = content
|
||||
.map((e) => BillProvider.fromJson(e as Map<String, dynamic>))
|
||||
.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<ApiResponse<List<BillProduct>>> 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<dynamic> list = response is List
|
||||
? response
|
||||
: (response['content'] ?? []);
|
||||
model.products = list
|
||||
.map((e) => BillProduct.fromJson(e as Map<String, dynamic>))
|
||||
.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<ApiResponse<List<PaymentProcessor>>> 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<dynamic> list = response is List
|
||||
? response
|
||||
: (response['content'] ?? []);
|
||||
model.processors = list
|
||||
.map((e) => PaymentProcessor.fromJson(e as Map<String, dynamic>))
|
||||
.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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user