add payments screen
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
/// Providers: Invoices
|
||||
///
|
||||
/// Riverpod providers for managing invoices state.
|
||||
library;
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:worker/core/database/models/enums.dart';
|
||||
import 'package:worker/features/orders/data/datasources/invoices_local_datasource.dart';
|
||||
import 'package:worker/features/orders/data/models/invoice_model.dart';
|
||||
|
||||
part 'invoices_provider.g.dart';
|
||||
|
||||
/// Invoices Local Data Source Provider
|
||||
@riverpod
|
||||
InvoicesLocalDataSource invoicesLocalDataSource(Ref ref) {
|
||||
return InvoicesLocalDataSource();
|
||||
}
|
||||
|
||||
/// Invoices Provider
|
||||
///
|
||||
/// Provides list of all invoices from local data source.
|
||||
@riverpod
|
||||
class Invoices extends _$Invoices {
|
||||
@override
|
||||
Future<List<InvoiceModel>> build() async {
|
||||
return await ref.read(invoicesLocalDataSourceProvider).getAllInvoices();
|
||||
}
|
||||
|
||||
/// Refresh invoices
|
||||
Future<void> refresh() async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
return await ref.read(invoicesLocalDataSourceProvider).getAllInvoices();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Selected Invoice Status Filter Provider
|
||||
///
|
||||
/// Tracks the currently selected invoice status filter for tabs.
|
||||
/// null means "All" invoices.
|
||||
@riverpod
|
||||
class SelectedInvoiceStatusFilter extends _$SelectedInvoiceStatusFilter {
|
||||
@override
|
||||
String? build() {
|
||||
return null; // Default: show all invoices
|
||||
}
|
||||
|
||||
/// Select a status filter
|
||||
void selectStatus(String? status) {
|
||||
state = status;
|
||||
}
|
||||
|
||||
/// Clear selection (show all)
|
||||
void clearSelection() {
|
||||
state = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Filtered Invoices Provider
|
||||
///
|
||||
/// Filters invoices by selected status tab.
|
||||
@riverpod
|
||||
Future<List<InvoiceModel>> filteredInvoices(Ref ref) async {
|
||||
final invoicesAsync = ref.watch(invoicesProvider);
|
||||
final selectedStatus = ref.watch(selectedInvoiceStatusFilterProvider);
|
||||
|
||||
return invoicesAsync.when(
|
||||
data: (invoices) {
|
||||
var filtered = invoices;
|
||||
|
||||
// Filter by status tab
|
||||
if (selectedStatus != null) {
|
||||
if (selectedStatus == 'unpaid') {
|
||||
// Unpaid tab: issued status only
|
||||
filtered = filtered
|
||||
.where((invoice) => invoice.status == InvoiceStatus.issued && !invoice.isPaid)
|
||||
.toList();
|
||||
} else if (selectedStatus == 'overdue') {
|
||||
// Overdue tab: overdue status
|
||||
filtered = filtered
|
||||
.where((invoice) => invoice.status == InvoiceStatus.overdue || invoice.isOverdue)
|
||||
.toList();
|
||||
} else if (selectedStatus == 'paid') {
|
||||
// Paid tab: paid status
|
||||
filtered = filtered
|
||||
.where((invoice) => invoice.status == InvoiceStatus.paid || invoice.isPaid)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by issue date (newest first)
|
||||
filtered.sort((a, b) => b.issueDate.compareTo(a.issueDate));
|
||||
|
||||
return filtered;
|
||||
},
|
||||
loading: () => [],
|
||||
error: (error, stack) => [],
|
||||
);
|
||||
}
|
||||
|
||||
/// Invoices Count by Status Provider
|
||||
///
|
||||
/// Returns count of invoices for each status tab.
|
||||
@riverpod
|
||||
Future<Map<String, int>> invoicesCountByStatus(Ref ref) async {
|
||||
final invoicesAsync = ref.watch(invoicesProvider);
|
||||
|
||||
return invoicesAsync.when(
|
||||
data: (invoices) {
|
||||
final counts = <String, int>{};
|
||||
|
||||
// All tab
|
||||
counts['all'] = invoices.length;
|
||||
|
||||
// Unpaid tab (issued status)
|
||||
counts['unpaid'] = invoices
|
||||
.where((invoice) => invoice.status == InvoiceStatus.issued && !invoice.isPaid)
|
||||
.length;
|
||||
|
||||
// Overdue tab
|
||||
counts['overdue'] = invoices
|
||||
.where((invoice) => invoice.status == InvoiceStatus.overdue || invoice.isOverdue)
|
||||
.length;
|
||||
|
||||
// Paid tab
|
||||
counts['paid'] = invoices
|
||||
.where((invoice) => invoice.status == InvoiceStatus.paid || invoice.isPaid)
|
||||
.length;
|
||||
|
||||
return counts;
|
||||
},
|
||||
loading: () => {},
|
||||
error: (error, stack) => {},
|
||||
);
|
||||
}
|
||||
|
||||
/// Total Invoices Amount Provider
|
||||
///
|
||||
/// Returns total amount of all invoices.
|
||||
@riverpod
|
||||
Future<double> totalInvoicesAmount(Ref ref) async {
|
||||
final invoicesAsync = ref.watch(invoicesProvider);
|
||||
|
||||
return invoicesAsync.when(
|
||||
data: (invoices) {
|
||||
return invoices.fold<double>(0.0, (sum, invoice) => sum + invoice.totalAmount);
|
||||
},
|
||||
loading: () => 0.0,
|
||||
error: (error, stack) => 0.0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Total Unpaid Amount Provider
|
||||
///
|
||||
/// Returns total amount remaining across all unpaid invoices.
|
||||
@riverpod
|
||||
Future<double> totalUnpaidAmount(Ref ref) async {
|
||||
final invoicesAsync = ref.watch(invoicesProvider);
|
||||
|
||||
return invoicesAsync.when(
|
||||
data: (invoices) {
|
||||
return invoices.fold<double>(0.0, (sum, invoice) => sum + invoice.amountRemaining);
|
||||
},
|
||||
loading: () => 0.0,
|
||||
error: (error, stack) => 0.0,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user