This commit is contained in:
Phuoc Nguyen
2025-10-10 16:38:07 +07:00
parent e5b247d622
commit b94c158004
177 changed files with 25080 additions and 152 deletions

View File

@@ -0,0 +1,27 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'cart_provider.dart';
part 'cart_item_count_provider.g.dart';
/// Provider that calculates total number of items in cart
/// This is optimized to only rebuild when the count changes
@riverpod
int cartItemCount(Ref ref) {
final itemsAsync = ref.watch(cartProvider);
return itemsAsync.when(
data: (items) => items.fold<int>(0, (sum, item) => sum + item.quantity),
loading: () => 0,
error: (_, __) => 0,
);
}
/// Provider that calculates unique items count in cart
@riverpod
int cartUniqueItemCount(Ref ref) {
final itemsAsync = ref.watch(cartProvider);
return itemsAsync.when(
data: (items) => items.length,
loading: () => 0,
error: (_, __) => 0,
);
}

View File

@@ -0,0 +1,104 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'cart_item_count_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Provider that calculates total number of items in cart
/// This is optimized to only rebuild when the count changes
@ProviderFor(cartItemCount)
const cartItemCountProvider = CartItemCountProvider._();
/// Provider that calculates total number of items in cart
/// This is optimized to only rebuild when the count changes
final class CartItemCountProvider extends $FunctionalProvider<int, int, int>
with $Provider<int> {
/// Provider that calculates total number of items in cart
/// This is optimized to only rebuild when the count changes
const CartItemCountProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'cartItemCountProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$cartItemCountHash();
@$internal
@override
$ProviderElement<int> $createElement($ProviderPointer pointer) =>
$ProviderElement(pointer);
@override
int create(Ref ref) {
return cartItemCount(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(int value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<int>(value),
);
}
}
String _$cartItemCountHash() => r'78fe81648a02fb84477df3be3f08b27caa039203';
/// Provider that calculates unique items count in cart
@ProviderFor(cartUniqueItemCount)
const cartUniqueItemCountProvider = CartUniqueItemCountProvider._();
/// Provider that calculates unique items count in cart
final class CartUniqueItemCountProvider
extends $FunctionalProvider<int, int, int>
with $Provider<int> {
/// Provider that calculates unique items count in cart
const CartUniqueItemCountProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'cartUniqueItemCountProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$cartUniqueItemCountHash();
@$internal
@override
$ProviderElement<int> $createElement($ProviderPointer pointer) =>
$ProviderElement(pointer);
@override
int create(Ref ref) {
return cartUniqueItemCount(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(int value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<int>(value),
);
}
}
String _$cartUniqueItemCountHash() =>
r'51eec092c957d0d4819200fd935115db77c7f8d3';

View File

@@ -0,0 +1,54 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../domain/entities/cart_item.dart';
part 'cart_provider.g.dart';
/// Provider for shopping cart
@riverpod
class Cart extends _$Cart {
@override
Future<List<CartItem>> build() async {
// TODO: Implement with repository
return [];
}
Future<void> addItem(CartItem item) async {
// TODO: Implement add to cart
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
final currentItems = state.value ?? [];
return [...currentItems, item];
});
}
Future<void> removeItem(String productId) async {
// TODO: Implement remove from cart
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
final currentItems = state.value ?? [];
return currentItems.where((item) => item.productId != productId).toList();
});
}
Future<void> updateQuantity(String productId, int quantity) async {
// TODO: Implement update quantity
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
final currentItems = state.value ?? [];
return currentItems.map((item) {
if (item.productId == productId) {
return item.copyWith(quantity: quantity);
}
return item;
}).toList();
});
}
Future<void> clearCart() async {
// TODO: Implement clear cart
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return [];
});
}
}

View File

@@ -0,0 +1,59 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'cart_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Provider for shopping cart
@ProviderFor(Cart)
const cartProvider = CartProvider._();
/// Provider for shopping cart
final class CartProvider extends $AsyncNotifierProvider<Cart, List<CartItem>> {
/// Provider for shopping cart
const CartProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'cartProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$cartHash();
@$internal
@override
Cart create() => Cart();
}
String _$cartHash() => r'0136ac2c2a04412a130184e30c01e33a17b0d4db';
/// Provider for shopping cart
abstract class _$Cart extends $AsyncNotifier<List<CartItem>> {
FutureOr<List<CartItem>> build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<AsyncValue<List<CartItem>>, List<CartItem>>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<AsyncValue<List<CartItem>>, List<CartItem>>,
AsyncValue<List<CartItem>>,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -0,0 +1,83 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'cart_provider.dart';
import '../../../settings/presentation/providers/settings_provider.dart';
part 'cart_total_provider.g.dart';
/// Cart totals calculation provider
@riverpod
class CartTotal extends _$CartTotal {
@override
CartTotalData build() {
final itemsAsync = ref.watch(cartProvider);
final settingsAsync = ref.watch(settingsProvider);
final items = itemsAsync.when(
data: (data) => data,
loading: () => <dynamic>[],
error: (_, __) => <dynamic>[],
);
final settings = settingsAsync.when(
data: (data) => data,
loading: () => null,
error: (_, __) => null,
);
// Calculate subtotal
final subtotal = items.fold<double>(
0.0,
(sum, item) => sum + item.lineTotal,
);
// Calculate tax
final taxRate = settings?.taxRate ?? 0.0;
final tax = subtotal * taxRate;
// Calculate total
final total = subtotal + tax;
return CartTotalData(
subtotal: subtotal,
tax: tax,
taxRate: taxRate,
total: total,
itemCount: items.length,
);
}
/// Apply discount amount to total
double applyDiscount(double discountAmount) {
final currentTotal = state.total;
return (currentTotal - discountAmount).clamp(0.0, double.infinity);
}
/// Apply discount percentage to total
double applyDiscountPercentage(double discountPercent) {
final currentTotal = state.total;
final discountAmount = currentTotal * (discountPercent / 100);
return (currentTotal - discountAmount).clamp(0.0, double.infinity);
}
}
/// Cart total data model
class CartTotalData {
final double subtotal;
final double tax;
final double taxRate;
final double total;
final int itemCount;
const CartTotalData({
required this.subtotal,
required this.tax,
required this.taxRate,
required this.total,
required this.itemCount,
});
@override
String toString() {
return 'CartTotalData(subtotal: $subtotal, tax: $tax, total: $total, items: $itemCount)';
}
}

View File

@@ -0,0 +1,68 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'cart_total_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Cart totals calculation provider
@ProviderFor(CartTotal)
const cartTotalProvider = CartTotalProvider._();
/// Cart totals calculation provider
final class CartTotalProvider
extends $NotifierProvider<CartTotal, CartTotalData> {
/// Cart totals calculation provider
const CartTotalProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'cartTotalProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$cartTotalHash();
@$internal
@override
CartTotal create() => CartTotal();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(CartTotalData value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<CartTotalData>(value),
);
}
}
String _$cartTotalHash() => r'044f6d4749eec49f9ef4173fc42d149a3841df21';
/// Cart totals calculation provider
abstract class _$CartTotal extends $Notifier<CartTotalData> {
CartTotalData build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<CartTotalData, CartTotalData>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<CartTotalData, CartTotalData>,
CartTotalData,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}

View File

@@ -0,0 +1,4 @@
/// Export all home/cart providers
export 'cart_provider.dart';
export 'cart_total_provider.dart';
export 'cart_item_count_provider.dart';