update cart/favorite
This commit is contained in:
@@ -71,7 +71,12 @@ class FavoriteProducts extends _$FavoriteProducts {
|
||||
@override
|
||||
Future<List<Product>> build() async {
|
||||
_repository = await ref.read(favoritesRepositoryProvider.future);
|
||||
return await _loadProducts();
|
||||
final products = await _loadProducts();
|
||||
|
||||
// Sync local IDs after loading
|
||||
ref.read(favoriteIdsLocalProvider.notifier).refresh();
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
@@ -99,20 +104,22 @@ class FavoriteProducts extends _$FavoriteProducts {
|
||||
|
||||
/// Add a product to favorites
|
||||
///
|
||||
/// Calls API to add to wishlist, then refreshes the products list.
|
||||
/// Calls API to add to wishlist, updates local state only (no refetch).
|
||||
/// No userId needed - the API uses the authenticated session.
|
||||
Future<void> addFavorite(String productId) async {
|
||||
try {
|
||||
_debugPrint('Adding product to favorites: $productId');
|
||||
|
||||
// Optimistically update local state first for instant UI feedback
|
||||
ref.read(favoriteIdsLocalProvider.notifier).addId(productId);
|
||||
|
||||
// Call repository to add to favorites (uses auth token from session)
|
||||
await _repository.addFavorite(productId);
|
||||
|
||||
// Refresh the products list after successful addition
|
||||
await refresh();
|
||||
|
||||
_debugPrint('Successfully added favorite: $productId');
|
||||
} catch (e) {
|
||||
// Rollback optimistic update on error
|
||||
ref.read(favoriteIdsLocalProvider.notifier).removeId(productId);
|
||||
_debugPrint('Error adding favorite: $e');
|
||||
rethrow;
|
||||
}
|
||||
@@ -120,20 +127,22 @@ class FavoriteProducts extends _$FavoriteProducts {
|
||||
|
||||
/// Remove a product from favorites
|
||||
///
|
||||
/// Calls API to remove from wishlist, then refreshes the products list.
|
||||
/// Calls API to remove from wishlist, updates local state only (no refetch).
|
||||
/// No userId needed - the API uses the authenticated session.
|
||||
Future<void> removeFavorite(String productId) async {
|
||||
try {
|
||||
_debugPrint('Removing product from favorites: $productId');
|
||||
|
||||
// Optimistically update local state first for instant UI feedback
|
||||
ref.read(favoriteIdsLocalProvider.notifier).removeId(productId);
|
||||
|
||||
// Call repository to remove from favorites (uses auth token from session)
|
||||
await _repository.removeFavorite(productId);
|
||||
|
||||
// Refresh the products list after successful removal
|
||||
await refresh();
|
||||
|
||||
_debugPrint('Successfully removed favorite: $productId');
|
||||
} catch (e) {
|
||||
// Rollback optimistic update on error
|
||||
ref.read(favoriteIdsLocalProvider.notifier).addId(productId);
|
||||
_debugPrint('Error removing favorite: $e');
|
||||
rethrow;
|
||||
}
|
||||
@@ -143,9 +152,11 @@ class FavoriteProducts extends _$FavoriteProducts {
|
||||
///
|
||||
/// If the product is favorited, it will be removed.
|
||||
/// If the product is not favorited, it will be added.
|
||||
/// Checks from local state for instant response.
|
||||
Future<void> toggleFavorite(String productId) async {
|
||||
final currentProducts = state.value ?? [];
|
||||
final isFavorited = currentProducts.any((p) => p.productId == productId);
|
||||
// Check from local IDs (instant, no API call)
|
||||
final localIds = ref.read(favoriteIdsLocalProvider);
|
||||
final isFavorited = localIds.contains(productId);
|
||||
|
||||
if (isFavorited) {
|
||||
await removeFavorite(productId);
|
||||
@@ -170,20 +181,48 @@ class FavoriteProducts extends _$FavoriteProducts {
|
||||
// HELPER PROVIDERS
|
||||
// ============================================================================
|
||||
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
@riverpod
|
||||
bool isFavorite(Ref ref, String productId) {
|
||||
final favoriteProductsAsync = ref.watch(favoriteProductsProvider);
|
||||
// Watch the notifier state to trigger rebuild when favorites change
|
||||
// But check from local Hive directly for instant response
|
||||
ref.watch(favoriteIdsLocalProvider);
|
||||
|
||||
return favoriteProductsAsync.when(
|
||||
data: (products) => products.any((p) => p.productId == productId),
|
||||
loading: () => false,
|
||||
error: (_, __) => false,
|
||||
);
|
||||
final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
|
||||
return localDataSource.isFavorite(productId);
|
||||
}
|
||||
|
||||
/// Local favorite IDs provider (synced with Hive)
|
||||
///
|
||||
/// This provider watches Hive changes and provides a Set of favorite product IDs.
|
||||
/// Used to trigger rebuilds when favorites are added/removed.
|
||||
@Riverpod(keepAlive: true)
|
||||
class FavoriteIdsLocal extends _$FavoriteIdsLocal {
|
||||
@override
|
||||
Set<String> build() {
|
||||
final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
|
||||
return localDataSource.getFavoriteIds();
|
||||
}
|
||||
|
||||
/// Refresh from local storage
|
||||
void refresh() {
|
||||
final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
|
||||
state = localDataSource.getFavoriteIds();
|
||||
}
|
||||
|
||||
/// Add a product ID to local state
|
||||
void addId(String productId) {
|
||||
state = {...state, productId};
|
||||
}
|
||||
|
||||
/// Remove a product ID from local state
|
||||
void removeId(String productId) {
|
||||
state = {...state}..remove(productId);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the total count of favorites
|
||||
|
||||
@@ -231,7 +231,7 @@ final class FavoriteProductsProvider
|
||||
FavoriteProducts create() => FavoriteProducts();
|
||||
}
|
||||
|
||||
String _$favoriteProductsHash() => r'd43c41db210259021df104f9fecdd00cf474d196';
|
||||
String _$favoriteProductsHash() => r'6d042f469a1f71bb06f8b5b76014bf24e30e6758';
|
||||
|
||||
/// Manages favorite products with full Product data from wishlist API
|
||||
///
|
||||
@@ -269,28 +269,28 @@ abstract class _$FavoriteProducts extends $AsyncNotifier<List<Product>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
|
||||
@ProviderFor(isFavorite)
|
||||
const isFavoriteProvider = IsFavoriteFamily._();
|
||||
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
|
||||
final class IsFavoriteProvider extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
const IsFavoriteProvider._({
|
||||
required IsFavoriteFamily super.from,
|
||||
required String super.argument,
|
||||
@@ -342,13 +342,13 @@ final class IsFavoriteProvider extends $FunctionalProvider<bool, bool, bool>
|
||||
}
|
||||
}
|
||||
|
||||
String _$isFavoriteHash() => r'6e2f5a50d2350975e17d91f395595cd284b69c20';
|
||||
String _$isFavoriteHash() => r'7aa2377f37ceb2c450c9e29b5c134ba160e4ecc2';
|
||||
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
|
||||
final class IsFavoriteFamily extends $Family
|
||||
with $FunctionalFamilyOverride<bool, String> {
|
||||
@@ -361,11 +361,11 @@ final class IsFavoriteFamily extends $Family
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// Check if a specific product is favorited
|
||||
/// Check if a specific product is favorited (LOCAL ONLY - no API call)
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
/// Returns true if the product is in the user's favorites, false otherwise.
|
||||
/// Safe to use in build methods - will return false during loading/error states.
|
||||
/// Reads directly from Hive local cache for instant response.
|
||||
/// This is used in product detail page to avoid unnecessary API calls.
|
||||
/// The cache is synced when favorites are loaded or modified.
|
||||
|
||||
IsFavoriteProvider call(String productId) =>
|
||||
IsFavoriteProvider._(argument: productId, from: this);
|
||||
@@ -374,6 +374,77 @@ final class IsFavoriteFamily extends $Family
|
||||
String toString() => r'isFavoriteProvider';
|
||||
}
|
||||
|
||||
/// Local favorite IDs provider (synced with Hive)
|
||||
///
|
||||
/// This provider watches Hive changes and provides a Set of favorite product IDs.
|
||||
/// Used to trigger rebuilds when favorites are added/removed.
|
||||
|
||||
@ProviderFor(FavoriteIdsLocal)
|
||||
const favoriteIdsLocalProvider = FavoriteIdsLocalProvider._();
|
||||
|
||||
/// Local favorite IDs provider (synced with Hive)
|
||||
///
|
||||
/// This provider watches Hive changes and provides a Set of favorite product IDs.
|
||||
/// Used to trigger rebuilds when favorites are added/removed.
|
||||
final class FavoriteIdsLocalProvider
|
||||
extends $NotifierProvider<FavoriteIdsLocal, Set<String>> {
|
||||
/// Local favorite IDs provider (synced with Hive)
|
||||
///
|
||||
/// This provider watches Hive changes and provides a Set of favorite product IDs.
|
||||
/// Used to trigger rebuilds when favorites are added/removed.
|
||||
const FavoriteIdsLocalProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'favoriteIdsLocalProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$favoriteIdsLocalHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
FavoriteIdsLocal create() => FavoriteIdsLocal();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Set<String> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Set<String>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$favoriteIdsLocalHash() => r'db248bc6dcd8ba39d8c3e410188cac67ebf96140';
|
||||
|
||||
/// Local favorite IDs provider (synced with Hive)
|
||||
///
|
||||
/// This provider watches Hive changes and provides a Set of favorite product IDs.
|
||||
/// Used to trigger rebuilds when favorites are added/removed.
|
||||
|
||||
abstract class _$FavoriteIdsLocal extends $Notifier<Set<String>> {
|
||||
Set<String> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<Set<String>, Set<String>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<Set<String>, Set<String>>,
|
||||
Set<String>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the total count of favorites
|
||||
///
|
||||
/// Derived from the favorite products list.
|
||||
|
||||
Reference in New Issue
Block a user