Files
Kifi/kifi-app/lib/features/transactions/providers/providers.dart
2026-08-16 20:13:21 +05:30

222 lines
7.5 KiB
Dart

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../data/repository.dart';
import '../data/models.dart';
final apiRepositoryProvider = Provider((ref) => ApiRepository());
class CategoryNotifier extends AsyncNotifier<List<Category>> {
@override
FutureOr<List<Category>> build() {
return ref.watch(apiRepositoryProvider).getCategories();
}
Future<void> addCategory(String name, String? iconName) async {
final newCategory = await ref.read(apiRepositoryProvider).addCategory(Category(id: 0, name: name, iconName: iconName));
if (state.value != null) {
state = AsyncValue.data([...state.value!, newCategory]);
}
}
}
final categoryProvider = AsyncNotifierProvider<CategoryNotifier, List<Category>>(() => CategoryNotifier());
class TransactionNotifier extends AsyncNotifier<List<Transaction>> {
@override
FutureOr<List<Transaction>> build() {
return ref.watch(apiRepositoryProvider).getTransactions();
}
Future<void> addTransaction(Transaction transaction, {List<Map<String, String>>? base64Attachments}) async {
final newTransaction = await ref.read(apiRepositoryProvider).addTransaction(transaction);
// Upload attachments if any
if (base64Attachments != null && base64Attachments.isNotEmpty) {
for (var attachment in base64Attachments) {
await ref.read(apiRepositoryProvider).addAttachment(
newTransaction.id,
attachment['fileName']!,
attachment['contentType']!,
attachment['base64Content']!
);
}
}
if (state.value != null) {
// Re-fetch transactions to get the fully populated transaction with attachments from backend
ref.invalidateSelf();
}
}
Future<void> updateTransaction(Transaction transaction, {List<Map<String, String>>? base64Attachments, List<int>? deletedAttachmentIds}) async {
final updatedTransaction = await ref.read(apiRepositoryProvider).updateTransaction(transaction);
bool hasChanges = false;
if (base64Attachments != null && base64Attachments.isNotEmpty) {
for (var attachment in base64Attachments) {
await ref.read(apiRepositoryProvider).addAttachment(
updatedTransaction.id,
attachment['fileName']!,
attachment['contentType']!,
attachment['base64Content']!
);
}
hasChanges = true;
}
if (deletedAttachmentIds != null && deletedAttachmentIds.isNotEmpty) {
for (var id in deletedAttachmentIds) {
await ref.read(apiRepositoryProvider).deleteAttachment(id);
}
hasChanges = true;
}
if (hasChanges) {
ref.invalidateSelf();
} else {
if (state.value != null) {
final updatedList = state.value!.map((t) => t.id == updatedTransaction.id ? updatedTransaction : t).toList();
state = AsyncValue.data(updatedList);
}
}
}
Future<void> deleteTransaction(int id) async {
await ref.read(apiRepositoryProvider).deleteTransaction(id);
if (state.value != null) {
state = AsyncValue.data(state.value!.where((t) => t.id != id).toList());
}
}
Future<void> closeInvestment(int id, double maturityAmount, DateTime closingDate, int toWalletId) async {
final updatedTransaction = await ref.read(apiRepositoryProvider).closeInvestment(id, maturityAmount, closingDate, toWalletId);
if (state.value != null) {
final updatedList = state.value!.map((t) => t.id == updatedTransaction.id ? updatedTransaction : t).toList();
state = AsyncValue.data(updatedList);
}
}
}
final transactionProvider = AsyncNotifierProvider<TransactionNotifier, List<Transaction>>(() => TransactionNotifier());
class BudgetNotifier extends AsyncNotifier<List<Budget>> {
@override
FutureOr<List<Budget>> build() {
return ref.watch(apiRepositoryProvider).getBudgets();
}
Future<void> addOrUpdateBudget(Budget budget) async {
final updatedBudget = await ref.read(apiRepositoryProvider).addOrUpdateBudget(budget);
if (state.value != null) {
final list = List<Budget>.from(state.value!);
final index = list.indexWhere((b) =>
(b.categoryId != null && b.categoryId == budget.categoryId) ||
(b.walletId != null && b.walletId == budget.walletId)
);
if (index >= 0) {
list[index] = updatedBudget;
} else {
list.add(updatedBudget);
}
state = AsyncValue.data(list);
}
}
}
final budgetProvider = AsyncNotifierProvider<BudgetNotifier, List<Budget>>(() => BudgetNotifier());
class RecurringTransactionNotifier extends AsyncNotifier<List<RecurringTransaction>> {
@override
FutureOr<List<RecurringTransaction>> build() {
return ref.watch(apiRepositoryProvider).getRecurringTransactions();
}
Future<void> addRecurringTransaction(RecurringTransaction rt) async {
final newRt = await ref.read(apiRepositoryProvider).addRecurringTransaction(rt);
if (state.value != null) {
state = AsyncValue.data([newRt, ...state.value!]);
}
}
}
final recurringTransactionProvider = AsyncNotifierProvider<RecurringTransactionNotifier, List<RecurringTransaction>>(() => RecurringTransactionNotifier());
class WalletNotifier extends AsyncNotifier<List<Wallet>> {
@override
FutureOr<List<Wallet>> build() {
return ref.watch(apiRepositoryProvider).getWallets();
}
Future<Wallet> createWallet({
required String name,
String nature = 'CASH',
double initialBalance = 0.0,
String currency = 'INR',
String? icon,
String? color,
}) async {
final newWallet = await ref.read(apiRepositoryProvider).createWallet(
name: name,
nature: nature,
initialBalance: initialBalance,
currency: currency,
icon: icon,
color: color,
);
if (state.value != null) {
state = AsyncValue.data([...state.value!, newWallet]);
}
return newWallet;
}
Future<void> inviteUser(int walletId, String email) async {
await ref.read(apiRepositoryProvider).inviteUserToWallet(walletId, email);
}
Future<void> editWallet(int id, {String? name, String? nature, String? icon, String? color}) async {
final updated = await ref.read(apiRepositoryProvider).editWallet(
id: id,
name: name,
nature: nature,
icon: icon,
color: color,
);
if (state.value != null) {
state = AsyncValue.data(
state.value!.map((w) => w.id == id ? updated : w).toList(),
);
}
}
Future<void> deleteWallet(int id) async {
await ref.read(apiRepositoryProvider).deleteWallet(id);
if (state.value != null) {
state = AsyncValue.data(
state.value!.where((w) => w.id != id).toList(),
);
}
}
}
class InvitationNotifier extends AsyncNotifier<List<WalletInvitation>> {
@override
Future<List<WalletInvitation>> build() async {
return ref.read(apiRepositoryProvider).getInvitations();
}
Future<void> acceptInvitation(int invitationId) async {
await ref.read(apiRepositoryProvider).acceptInvitation(invitationId);
state = AsyncValue.data(state.value?.where((inv) => inv.id != invitationId).toList() ?? []);
ref.invalidate(walletProvider); // Refresh wallets
}
Future<void> rejectInvitation(int invitationId) async {
await ref.read(apiRepositoryProvider).rejectInvitation(invitationId);
state = AsyncValue.data(state.value?.where((inv) => inv.id != invitationId).toList() ?? []);
}
}
final walletProvider = AsyncNotifierProvider<WalletNotifier, List<Wallet>>(() => WalletNotifier());
final invitationProvider = AsyncNotifierProvider<InvitationNotifier, List<WalletInvitation>>(() => InvitationNotifier());