Files
worker/lib/features/quotes/presentation/providers/quotes_provider.dart
2025-11-07 11:52:06 +07:00

143 lines
3.5 KiB
Dart

/// Providers: Quotes
///
/// Riverpod providers for managing quotes state.
library;
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/database/models/enums.dart';
import 'package:worker/features/quotes/data/datasources/quotes_local_datasource.dart';
import 'package:worker/features/quotes/data/models/quote_model.dart';
part 'quotes_provider.g.dart';
/// Quotes Local Data Source Provider
@riverpod
QuotesLocalDataSource quotesLocalDataSource(Ref ref) {
return QuotesLocalDataSource();
}
/// Quotes Provider
///
/// Provides list of all quotes from local data source.
@riverpod
class Quotes extends _$Quotes {
@override
Future<List<QuoteModel>> build() async {
final datasource = ref.read(quotesLocalDataSourceProvider);
// Seed mock data on first load
final quotes = await datasource.getAllQuotes();
if (quotes.isEmpty) {
await datasource.seedMockQuotes();
return await datasource.getAllQuotes();
}
return quotes;
}
/// Refresh quotes
Future<void> refresh() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return await ref.read(quotesLocalDataSourceProvider).getAllQuotes();
});
}
}
/// Quote Search Query Provider
@riverpod
class QuoteSearchQuery extends _$QuoteSearchQuery {
@override
String build() {
return '';
}
void updateQuery(String query) {
state = query;
}
void clearQuery() {
state = '';
}
}
/// Selected Quote Status Filter Provider
@riverpod
class SelectedQuoteStatus extends _$SelectedQuoteStatus {
@override
QuoteStatus? build() {
return null; // null means show all statuses
}
void selectStatus(QuoteStatus? status) {
state = status;
}
void clearFilter() {
state = null;
}
}
/// Filtered Quotes Provider
///
/// Filters quotes by search query and status.
@riverpod
Future<List<QuoteModel>> filteredQuotes(Ref ref) async {
final quotesAsync = ref.watch(quotesProvider);
final searchQuery = ref.watch(quoteSearchQueryProvider);
final selectedStatus = ref.watch(selectedQuoteStatusProvider);
return quotesAsync.when(
data: (quotes) {
var filtered = quotes;
// Filter by search query
if (searchQuery.isNotEmpty) {
final lowerQuery = searchQuery.toLowerCase();
filtered = filtered.where((quote) {
final matchesNumber = quote.quoteNumber.toLowerCase().contains(
lowerQuery,
);
final matchesProject =
quote.projectName?.toLowerCase().contains(lowerQuery) ?? false;
return matchesNumber || matchesProject;
}).toList();
}
// Filter by status
if (selectedStatus != null) {
filtered = filtered
.where((quote) => quote.status == selectedStatus)
.toList();
}
// Sort by creation date (newest first)
filtered.sort((a, b) => b.createdAt.compareTo(a.createdAt));
return filtered;
},
loading: () => [],
error: (error, stack) => [],
);
}
/// Quotes Count by Status Provider
@riverpod
Future<Map<QuoteStatus, int>> quotesCountByStatus(Ref ref) async {
final quotesAsync = ref.watch(quotesProvider);
return quotesAsync.when(
data: (quotes) {
final counts = <QuoteStatus, int>{};
for (final status in QuoteStatus.values) {
counts[status] = quotes.where((quote) => quote.status == status).length;
}
return counts;
},
loading: () => {},
error: (error, stack) => {},
);
}