import 'dart:convert'; import 'package:dio/dio.dart'; import '../../../../core/network/dio_client.dart'; import 'models.dart'; class ApiRepository { final Dio dio = DioClient().dio; Future> getCategories() async { final response = await dio.get('/categories'); return (response.data as List).map((j) => Category.fromJson(j)).toList(); } Future addCategory(Category category) async { final response = await dio.post('/categories', data: category.toJson()); return Category.fromJson(response.data); } Future> getTransactions() async { final response = await dio.get('/transactions'); return (response.data as List).map((j) => Transaction.fromJson(j)).toList(); } Future> searchTransactions({ String? type, int? walletId, int? categoryId, String? startDate, String? endDate, String? search, int page = 0, int size = 20, }) async { final queryParams = { if (type != null) 'type': type, if (walletId != null) 'walletId': walletId, if (categoryId != null) 'categoryId': categoryId, if (startDate != null) 'startDate': startDate, if (endDate != null) 'endDate': endDate, if (search != null && search.isNotEmpty) 'search': search, 'page': page, 'size': size, }; final response = await dio.get('/transactions/search', queryParameters: queryParams); final content = (response.data['content'] as List).map((j) => Transaction.fromJson(j)).toList(); final totalElements = response.data['totalElements'] as int; final totalPages = response.data['totalPages'] as int; return { 'content': content, 'totalElements': totalElements, 'totalPages': totalPages, }; } Future addTransaction(Transaction transaction) async { final response = await dio.post('/transactions', data: transaction.toJson()); return Transaction.fromJson(response.data); } Future updateTransaction(Transaction transaction) async { final response = await dio.put('/transactions/${transaction.id}', data: transaction.toJson()); return Transaction.fromJson(response.data); } Future deleteTransaction(int id) async { await dio.delete('/transactions/$id'); } Future addAttachment(int transactionId, String fileName, String contentType, String base64Content) async { final bytes = base64Decode(base64Content); final formData = FormData.fromMap({ 'file': MultipartFile.fromBytes(bytes, filename: fileName, contentType: DioMediaType.parse(contentType)), }); final response = await dio.post('/transactions/$transactionId/attachments', data: formData); return TransactionAttachment.fromJson(response.data); } Future deleteAttachment(int attachmentId) async { await dio.delete('/transactions/attachments/$attachmentId'); } Future closeInvestment(int transactionId, double maturityAmount, DateTime closingDate, int toWalletId) async { final response = await dio.put('/transactions/$transactionId/close-investment', data: { 'maturityAmount': maturityAmount, 'closingDate': closingDate.toIso8601String().split('T')[0], 'toWalletId': toWalletId, }); return Transaction.fromJson(response.data); } // Budgets Future> getBudgets() async { try { final response = await dio.get('/budgets'); if (response.data is List) { return (response.data as List).map((j) => Budget.fromJson(j)).toList(); } else if (response.data is Map && response.data.containsKey('data')) { return (response.data['data'] as List).map((j) => Budget.fromJson(j)).toList(); } return []; } catch (e) { print('Error fetching budgets: $e'); return []; } } Future addOrUpdateBudget(Budget budget) async { final response = await dio.post('/budgets', data: budget.toJson()); return Budget.fromJson(response.data); } // Recurring Transactions Future> getRecurringTransactions() async { final response = await dio.get('/recurring-transactions'); return (response.data as List).map((j) => RecurringTransaction.fromJson(j)).toList(); } Future addRecurringTransaction(RecurringTransaction rt) async { final response = await dio.post('/recurring-transactions', data: rt.toJson()); return RecurringTransaction.fromJson(response.data); } Future deleteRecurringTransaction(int id) async { await dio.delete('/recurring-transactions/$id'); } // Reports Future> exportTransactions() async { final response = await dio.get( '/reports/export', options: Options(responseType: ResponseType.bytes), ); return response.data; } // Wallets Future> getWallets() async { final response = await dio.get('/wallets'); return (response.data as List).map((j) => Wallet.fromJson(j)).toList(); } Future 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 response = await dio.post('/wallets', data: { 'name': name, 'nature': nature, 'initialBalance': initialBalance, 'currency': currency, 'icon': icon, 'color': color, if (subNature != null) 'subNature': subNature, if (creditLimit != null) 'creditLimit': creditLimit, if (fixedAmount != null) 'fixedAmount': fixedAmount, if (paymentCycle != null) 'paymentCycle': paymentCycle, if (cycleDate != null) 'cycleDate': cycleDate, }); return Wallet.fromJson(response.data); } Future editWallet({ required int id, String? name, String? nature, String? icon, String? color, String? subNature, double? creditLimit, double? fixedAmount, String? paymentCycle, int? cycleDate, }) async { final response = await dio.put('/wallets/$id', data: { if (name != null) 'name': name, if (nature != null) 'nature': nature, if (icon != null) 'icon': icon, if (color != null) 'color': color, if (subNature != null) 'subNature': subNature, if (creditLimit != null) 'creditLimit': creditLimit, if (fixedAmount != null) 'fixedAmount': fixedAmount, if (paymentCycle != null) 'paymentCycle': paymentCycle, if (cycleDate != null) 'cycleDate': cycleDate, }); return Wallet.fromJson(response.data); } Future deleteWallet(int id) async { try { await dio.delete('/wallets/$id'); } on DioException catch (e) { if (e.response != null && e.response!.data != null && e.response!.data is Map) { throw Exception(e.response!.data['error'] ?? 'Failed to delete wallet'); } throw Exception('Failed to delete wallet'); } } Future inviteUserToWallet(int walletId, String email) async { await dio.post('/wallets/$walletId/invite', data: {'email': email}); } Future> getInvitations() async { final response = await dio.get('/wallets/invitations'); return (response.data as List).map((x) => WalletInvitation.fromJson(x)).toList(); } Future acceptInvitation(int invitationId) async { await dio.post('/wallets/invitations/$invitationId/accept'); } Future rejectInvitation(int invitationId) async { await dio.post('/wallets/invitations/$invitationId/reject'); } Future> getWalletMembers(int walletId) async { final response = await dio.get('/wallets/$walletId/members'); return (response.data as List).map((x) => WalletMember.fromJson(x)).toList(); } Future removeWalletMember(int walletId, int memberId) async { await dio.delete('/wallets/$walletId/members/$memberId'); } Future> getKnownContacts() async { final response = await dio.get('/wallets/user-contacts'); return (response.data as List).map((x) => x.toString()).toList(); } }