241 lines
8.4 KiB
Dart
241 lines
8.4 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() async {
|
|
final wallets = await ref.watch(apiRepositoryProvider).getWallets();
|
|
wallets.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
|
|
return wallets;
|
|
}
|
|
|
|
Future<Wallet> createWallet({
|
|
required String name,
|
|
String nature = 'CASH',
|
|
double initialBalance = 0.0,
|
|
String currency = 'INR',
|
|
String? icon,
|
|
String? color,
|
|
String? subNature,
|
|
double? creditLimit,
|
|
double? fixedAmount,
|
|
String? paymentCycle,
|
|
int? cycleDate,
|
|
}) async {
|
|
final newWallet = await ref.read(apiRepositoryProvider).createWallet(
|
|
name: name,
|
|
nature: nature,
|
|
initialBalance: initialBalance,
|
|
currency: currency,
|
|
icon: icon,
|
|
color: color,
|
|
subNature: subNature,
|
|
creditLimit: creditLimit,
|
|
fixedAmount: fixedAmount,
|
|
paymentCycle: paymentCycle,
|
|
cycleDate: cycleDate,
|
|
);
|
|
if (state.value != null) {
|
|
final updated = [...state.value!, newWallet];
|
|
updated.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
|
|
state = AsyncValue.data(updated);
|
|
}
|
|
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, String? subNature, double? creditLimit, double? fixedAmount, String? paymentCycle, int? cycleDate}) async {
|
|
final updated = await ref.read(apiRepositoryProvider).editWallet(
|
|
id: id,
|
|
name: name,
|
|
nature: nature,
|
|
icon: icon,
|
|
color: color,
|
|
subNature: subNature,
|
|
creditLimit: creditLimit,
|
|
fixedAmount: fixedAmount,
|
|
paymentCycle: paymentCycle,
|
|
cycleDate: cycleDate,
|
|
);
|
|
if (state.value != null) {
|
|
final updatedList = state.value!.map((w) => w.id == id ? updated : w).toList();
|
|
updatedList.sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
|
|
state = AsyncValue.data(updatedList);
|
|
}
|
|
}
|
|
|
|
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());
|