Files
velocity-pay-flutter/lib/screens/home/home_controller.dart
2025-07-14 01:04:53 +02:00

248 lines
6.6 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:qpay/http/http.dart';
part 'home_controller.freezed.dart';
part 'home_controller.g.dart';
class HomeScreenModel {
List<Map<String, dynamic>> transactions = [];
List<Category> categories = [];
List<BillProvider> providers = [];
List<BillProvider> filterableProviders = [];
BillProvider? selectedProvider;
dynamic selectedCategory;
dynamic account = {};
dynamic profile = {};
bool isLoading = false;
bool isLoggedIn = false;
String? errorMessage;
}
@freezed
abstract class Category with _$Category {
const factory Category({
required String name,
required String description,
required String? image,
required String label,
}) = _Category;
factory Category.fromJson(Map<String, dynamic> json) =>
_$CategoryFromJson(json);
}
@freezed
abstract class BillProvider with _$BillProvider {
const factory BillProvider({
required String clientId,
required String name,
required String description,
required bool requiresAccount,
required bool requiresAmount,
required bool requiresAmountFromMerchant,
required bool requiresPhone,
required bool requiresReversal,
required String? additionalDataString,
required String processorType,
required String uid,
required String image,
required String label,
required String category,
required String? accountFieldName,
}) = _BillProvider;
factory BillProvider.fromJson(Map<String, dynamic> json) =>
_$BillProviderFromJson(json);
}
class HomeController extends ChangeNotifier {
final HomeScreenModel model = HomeScreenModel();
final Http http = Http();
BuildContext context;
HomeController(this.context);
void _showErrorSnackBar(String? message) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message.toString()),
behavior: SnackBarBehavior.floating,
backgroundColor: Colors.deepOrange,
),
);
});
}
Future<void> getProviders() async {
try {
model.isLoading = true;
notifyListeners();
List<dynamic> response = await http.get('/providers');
model.providers = response.map((e) => BillProvider.fromJson(e)).toList();
model.filterableProviders = model.providers;
if (model.providers.isNotEmpty) {
updateSelectedProvider(model.providers[0]);
}
} catch (e) {
logger.e(e);
_showErrorSnackBar(
"Problem fetching providers, are you connected to the internet?",
);
model.errorMessage = e.toString();
model.providers = [];
model.filterableProviders = [];
}
model.isLoading = false;
notifyListeners();
}
void updateSelectedProvider(BillProvider provider) {
model.selectedProvider = provider;
// getProducts(provider.uid);
notifyListeners();
}
Future<void> getTransactions(String userId) async {
model.isLoading = true;
notifyListeners();
try {
List<dynamic> response = await http.get(
'/transaction?userId=$userId&type=REQUEST',
);
model.transactions =
response.map((e) => e as Map<String, dynamic>).toList();
} catch (e) {
logger.e(e);
_showErrorSnackBar(
"Problem fetching transactions, are you connected to the internet?",
);
model.errorMessage = e.toString();
model.transactions = [];
} finally {
model.isLoading = false;
notifyListeners();
}
}
Future<void> getCategories() async {
// activate skeletonizer
model.categories = getFakeCategoryData();
model.transactions = getFakeTransactions();
// model.filterableProviders = getFakeProviders();
model.isLoading = true;
notifyListeners();
// Simulate fetching categories
try {
List<dynamic> response = await http.get('/categories');
model.categories = response.map((e) => Category.fromJson(e)).toList();
if (model.categories.isNotEmpty) {
updateSelectedCategory(model.categories[0]);
}
} on Exception catch (e) {
logger.e(e);
_showErrorSnackBar(
"Problem fetching categories, are you connected to the internet?",
);
model.errorMessage = e.toString();
model.categories = [];
} finally {
model.isLoading = false;
notifyListeners();
}
}
Future<void> updateSelectedCategory(Category? category) async {
if (category == null) {
model.filterableProviders = model.providers;
notifyListeners();
return;
}
model.selectedCategory = category;
model.filterableProviders =
model.providers
.where((element) => element.category == category.label)
.toList();
notifyListeners();
}
List<Map<String, dynamic>> getFakeTransactions() {
return [
{
"id": "77b2c479-b803-49fc-b5c3-acbf52cba633",
"trace": "22a3044b-8f53-4e43-b4f5-c77dcec48d2d",
"amount": 25.0,
"charge": 0.0,
"gatewayCharge": 0.25,
"tax": 0.5,
"totalAmount": 25.75,
"reference": "c838136c-c015-4a0b-9c7c-52f127c8c109",
"paymentProcessorLabel": "MPGS",
"paymentProcessorImage": "visa-mastercard.png",
"debitPhone": "",
"debitAccount": "",
"debitCurrency": "USD",
"debitRef": "peak",
"creditPhone": "",
"creditAccount": "07088597534",
"billClientId": "powertel_zesa",
"billName": "Zesa",
"type": "REQUEST",
"authType": "WEB",
"errorMessage": "",
"responseCode": "00",
"status": "SUCCESS",
"sdkActionId": "0aa0d90d-6132-48a7-a5d8-e796f757c73f",
},
];
}
List<BillProvider> getFakeProviders() {
return [
BillProvider(
clientId: '1',
name: 'ZESA',
description: 'Pay your electricity bills easily',
requiresAccount: false,
requiresAmount: false,
requiresAmountFromMerchant: false,
requiresPhone: false,
requiresReversal: false,
additionalDataString: '',
processorType: '',
uid: '',
image: 'econet.png',
label: '',
category: '',
accountFieldName: '',
),
];
}
// required by skeletonizer
List<Category> getFakeCategoryData() {
return [
Category(
name: 'Airtime',
description: 'Pay your electricity bills easily',
image: 'assets/images/electricity.png',
label: 'Electricity',
),
];
}
}