Files
velocity-pay-flutter/lib/screens/accounts/account_provider.dart
2026-06-24 18:01:34 +02:00

149 lines
4.1 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:qpay/http/http.dart';
import 'package:qpay/models/api_response.dart';
import 'package:qpay/screens/accounts/models/account_model.dart';
import 'package:qpay/screens/accounts/models/statement_model.dart';
class AccountProvider extends ChangeNotifier {
final Http http = Http();
AccountProvider();
AccountModel? _account;
StatementModel? _statement;
bool _isLoadingAccount = false;
bool _isLoadingStatement = false;
String? _accountError;
String? _statementError;
/// Cached balances keyed by currency code (e.g. 'USD', 'ZWG').
final Map<String, AccountModel?> _balances = {};
AccountModel? get account => _account;
StatementModel? get statement => _statement;
bool get isLoadingAccount => _isLoadingAccount;
bool get isLoadingStatement => _isLoadingStatement;
String? get accountError => _accountError;
String? get statementError => _statementError;
bool _isDisposed = false;
/// Returns a cached account balance for [currency], or null if not yet
/// fetched.
AccountModel? balanceForCurrency(String currency) {
return _balances[currency.toUpperCase()];
}
/// Returns the account with name 'City Wallet' for [currency], or null.
AccountModel? cityWalletBalance() {
return _balances.values.firstWhere(
(a) => a?.name == 'City Wallet',
orElse: () => null,
);
}
@override
void notifyListeners() {
if (!_isDisposed) {
super.notifyListeners();
}
}
@override
void dispose() {
_isDisposed = true;
super.dispose();
}
Future<ApiResponse<AccountModel>> fetchAccount(
String? workspaceId,
String currency,
) async {
_isLoadingAccount = true;
_accountError = null;
notifyListeners();
try {
Map<String, dynamic> response = await http.get(
'/accounts/$workspaceId/balance/$currency',
);
_account = AccountModel.fromJson(response);
_balances[currency.toUpperCase()] = _account;
_isLoadingAccount = false;
notifyListeners();
return ApiResponse.success(_account!);
} on DioException catch (e, s) {
logger.e(s);
_isLoadingAccount = false;
_accountError = 'Failed to fetch account. Please try again.';
notifyListeners();
return ApiResponse.failure(_accountError!);
} catch (e, s) {
logger.e(e);
logger.e(s);
_isLoadingAccount = false;
_accountError = 'An unexpected error occurred. Please try again.';
notifyListeners();
return ApiResponse.failure(_accountError!);
}
}
/// Pre-load multiple currency balances at once. Results are stored in the
/// [_balances] map so any widget can access them later.
Future<void> preloadBalances(
String? workspaceId,
List<String> currencies,
) async {
for (final currency in currencies) {
await fetchAccount(workspaceId, currency);
}
}
Future<ApiResponse<StatementModel>> fetchStatement({
required String workspaceId,
required String currency,
required String startDate,
required String endDate,
}) async {
_isLoadingStatement = true;
_statementError = null;
notifyListeners();
try {
Map<String, dynamic> response = await http.get(
'/accounts/$workspaceId/statement/$currency'
'?startDate=$startDate&endDate=$endDate',
);
_statement = StatementModel.fromJson(response);
_isLoadingStatement = false;
notifyListeners();
return ApiResponse.success(_statement!);
} on DioException catch (e, s) {
logger.e(s);
_isLoadingStatement = false;
_statementError = 'Failed to fetch statement. Please try again.';
notifyListeners();
return ApiResponse.failure(_statementError!);
} catch (e, s) {
logger.e(s);
_isLoadingStatement = false;
_statementError = 'An unexpected error occurred. Please try again.';
notifyListeners();
return ApiResponse.failure(_statementError!);
}
}
void clearAccount() {
_account = null;
_accountError = null;
notifyListeners();
}
void clearStatement() {
_statement = null;
_statementError = null;
notifyListeners();
}
}