add quotes

This commit is contained in:
Phuoc Nguyen
2025-10-27 15:30:31 +07:00
parent 7ce4239772
commit 3020c4e626
8 changed files with 1177 additions and 4 deletions

View File

@@ -0,0 +1,138 @@
/// 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) => {},
);
}

View File

@@ -0,0 +1,338 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'quotes_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Quotes Local Data Source Provider
@ProviderFor(quotesLocalDataSource)
const quotesLocalDataSourceProvider = QuotesLocalDataSourceProvider._();
/// Quotes Local Data Source Provider
final class QuotesLocalDataSourceProvider
extends
$FunctionalProvider<
QuotesLocalDataSource,
QuotesLocalDataSource,
QuotesLocalDataSource
>
with $Provider<QuotesLocalDataSource> {
/// Quotes Local Data Source Provider
const QuotesLocalDataSourceProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'quotesLocalDataSourceProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$quotesLocalDataSourceHash();
@$internal
@override
$ProviderElement<QuotesLocalDataSource> $createElement(
$ProviderPointer pointer,
) => $ProviderElement(pointer);
@override
QuotesLocalDataSource create(Ref ref) {
return quotesLocalDataSource(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(QuotesLocalDataSource value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<QuotesLocalDataSource>(value),
);
}
}
String _$quotesLocalDataSourceHash() =>
r'02a822db926d8d80460bcc27a08ea494dff6c441';
/// Quotes Provider
///
/// Provides list of all quotes from local data source.
@ProviderFor(Quotes)
const quotesProvider = QuotesProvider._();
/// Quotes Provider
///
/// Provides list of all quotes from local data source.
final class QuotesProvider
extends $AsyncNotifierProvider<Quotes, List<QuoteModel>> {
/// Quotes Provider
///
/// Provides list of all quotes from local data source.
const QuotesProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'quotesProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$quotesHash();
@$internal
@override
Quotes create() => Quotes();
}
String _$quotesHash() => r'f5011c354218f10da95af16269c956416fca3303';
/// Quotes Provider
///
/// Provides list of all quotes from local data source.
abstract class _$Quotes extends $AsyncNotifier<List<QuoteModel>> {
FutureOr<List<QuoteModel>> build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref =
this.ref as $Ref<AsyncValue<List<QuoteModel>>, List<QuoteModel>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<List<QuoteModel>>, List<QuoteModel>>,
AsyncValue<List<QuoteModel>>,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
/// Quote Search Query Provider
@ProviderFor(QuoteSearchQuery)
const quoteSearchQueryProvider = QuoteSearchQueryProvider._();
/// Quote Search Query Provider
final class QuoteSearchQueryProvider
extends $NotifierProvider<QuoteSearchQuery, String> {
/// Quote Search Query Provider
const QuoteSearchQueryProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'quoteSearchQueryProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$quoteSearchQueryHash();
@$internal
@override
QuoteSearchQuery create() => QuoteSearchQuery();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(String value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<String>(value),
);
}
}
String _$quoteSearchQueryHash() => r'cc889177beb9905a80b223cba14612bb0c419103';
/// Quote Search Query Provider
abstract class _$QuoteSearchQuery extends $Notifier<String> {
String build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<String, String>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<String, String>,
String,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
/// Selected Quote Status Filter Provider
@ProviderFor(SelectedQuoteStatus)
const selectedQuoteStatusProvider = SelectedQuoteStatusProvider._();
/// Selected Quote Status Filter Provider
final class SelectedQuoteStatusProvider
extends $NotifierProvider<SelectedQuoteStatus, QuoteStatus?> {
/// Selected Quote Status Filter Provider
const SelectedQuoteStatusProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'selectedQuoteStatusProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$selectedQuoteStatusHash();
@$internal
@override
SelectedQuoteStatus create() => SelectedQuoteStatus();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(QuoteStatus? value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<QuoteStatus?>(value),
);
}
}
String _$selectedQuoteStatusHash() =>
r'5c1ecf114bbb85a00174dad255c939288722658b';
/// Selected Quote Status Filter Provider
abstract class _$SelectedQuoteStatus extends $Notifier<QuoteStatus?> {
QuoteStatus? build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<QuoteStatus?, QuoteStatus?>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<QuoteStatus?, QuoteStatus?>,
QuoteStatus?,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
/// Filtered Quotes Provider
///
/// Filters quotes by search query and status.
@ProviderFor(filteredQuotes)
const filteredQuotesProvider = FilteredQuotesProvider._();
/// Filtered Quotes Provider
///
/// Filters quotes by search query and status.
final class FilteredQuotesProvider
extends
$FunctionalProvider<
AsyncValue<List<QuoteModel>>,
List<QuoteModel>,
FutureOr<List<QuoteModel>>
>
with $FutureModifier<List<QuoteModel>>, $FutureProvider<List<QuoteModel>> {
/// Filtered Quotes Provider
///
/// Filters quotes by search query and status.
const FilteredQuotesProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'filteredQuotesProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$filteredQuotesHash();
@$internal
@override
$FutureProviderElement<List<QuoteModel>> $createElement(
$ProviderPointer pointer,
) => $FutureProviderElement(pointer);
@override
FutureOr<List<QuoteModel>> create(Ref ref) {
return filteredQuotes(ref);
}
}
String _$filteredQuotesHash() => r'77076cfa483cb81cc56972bca6a3c1e97861165c';
/// Quotes Count by Status Provider
@ProviderFor(quotesCountByStatus)
const quotesCountByStatusProvider = QuotesCountByStatusProvider._();
/// Quotes Count by Status Provider
final class QuotesCountByStatusProvider
extends
$FunctionalProvider<
AsyncValue<Map<QuoteStatus, int>>,
Map<QuoteStatus, int>,
FutureOr<Map<QuoteStatus, int>>
>
with
$FutureModifier<Map<QuoteStatus, int>>,
$FutureProvider<Map<QuoteStatus, int>> {
/// Quotes Count by Status Provider
const QuotesCountByStatusProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'quotesCountByStatusProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$quotesCountByStatusHash();
@$internal
@override
$FutureProviderElement<Map<QuoteStatus, int>> $createElement(
$ProviderPointer pointer,
) => $FutureProviderElement(pointer);
@override
FutureOr<Map<QuoteStatus, int>> create(Ref ref) {
return quotesCountByStatus(ref);
}
}
String _$quotesCountByStatusHash() =>
r'474b62ad0ccf890df1c33c64a17f9a0f428f676e';