diff --git a/lib/core/providers/connectivity_provider.g.dart b/lib/core/providers/connectivity_provider.g.dart index 50ba65d..6755258 100644 --- a/lib/core/providers/connectivity_provider.g.dart +++ b/lib/core/providers/connectivity_provider.g.dart @@ -65,7 +65,7 @@ String _$connectivityHash() => r'6d67af0ea4110f6ee0246dd332f90f8901380eda'; /// final connectivityState = ref.watch(connectivityStreamProvider); /// connectivityState.when( /// data: (status) => Text('Status: $status'), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` @@ -81,7 +81,7 @@ const connectivityStreamProvider = ConnectivityStreamProvider._(); /// final connectivityState = ref.watch(connectivityStreamProvider); /// connectivityState.when( /// data: (status) => Text('Status: $status'), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` @@ -104,7 +104,7 @@ final class ConnectivityStreamProvider /// final connectivityState = ref.watch(connectivityStreamProvider); /// connectivityState.when( /// data: (status) => Text('Status: $status'), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` @@ -219,7 +219,7 @@ String _$currentConnectivityHash() => /// final isOnlineAsync = ref.watch(isOnlineProvider); /// isOnlineAsync.when( /// data: (isOnline) => isOnline ? Text('Online') : Text('Offline'), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` @@ -235,7 +235,7 @@ const isOnlineProvider = IsOnlineProvider._(); /// final isOnlineAsync = ref.watch(isOnlineProvider); /// isOnlineAsync.when( /// data: (isOnline) => isOnline ? Text('Online') : Text('Offline'), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` @@ -251,7 +251,7 @@ final class IsOnlineProvider /// final isOnlineAsync = ref.watch(isOnlineProvider); /// isOnlineAsync.when( /// data: (isOnline) => isOnline ? Text('Online') : Text('Offline'), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, _) => Text('Error: $error'), /// ); /// ``` diff --git a/lib/core/services/analytics_service.dart b/lib/core/services/analytics_service.dart index 4c03e79..19a84ab 100644 --- a/lib/core/services/analytics_service.dart +++ b/lib/core/services/analytics_service.dart @@ -52,13 +52,39 @@ class AnalyticsService { } } + // ============================================================================ + // E-commerce Events + // ============================================================================ + + /// Log view item event - when user views product detail + static Future logViewItem({ + required String productId, + required String productName, + required double price, + String? brand, + String? category, + }) async { + try { + await _analytics.logViewItem( + currency: 'VND', + value: price, + items: [ + AnalyticsEventItem( + itemId: productId, + itemName: productName, + price: price, + itemBrand: brand, + itemCategory: category, + ), + ], + ); + debugPrint('πŸ“Š Analytics: view_item - $productName'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + /// Log add to cart event - /// - /// [productId] - Product SKU or ID - /// [productName] - Product display name - /// [price] - Unit price in VND - /// [quantity] - Quantity added - /// [category] - Optional product category static Future logAddToCart({ required String productId, required String productName, @@ -85,4 +111,252 @@ class AnalyticsService { debugPrint('πŸ“Š Analytics error: $e'); } } + + /// Log remove from cart event + static Future logRemoveFromCart({ + required String productId, + required String productName, + required double price, + required int quantity, + }) async { + try { + await _analytics.logRemoveFromCart( + currency: 'VND', + value: price * quantity, + items: [ + AnalyticsEventItem( + itemId: productId, + itemName: productName, + price: price, + quantity: quantity, + ), + ], + ); + debugPrint('πŸ“Š Analytics: remove_from_cart - $productName'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log view cart event + static Future logViewCart({ + required double cartValue, + required List items, + }) async { + try { + await _analytics.logViewCart( + currency: 'VND', + value: cartValue, + items: items, + ); + debugPrint('πŸ“Š Analytics: view_cart - ${items.length} items'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log begin checkout event + static Future logBeginCheckout({ + required double value, + required List items, + String? coupon, + }) async { + try { + await _analytics.logBeginCheckout( + currency: 'VND', + value: value, + items: items, + coupon: coupon, + ); + debugPrint('πŸ“Š Analytics: begin_checkout - $value VND'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log purchase event - when order is completed + static Future logPurchase({ + required String orderId, + required double value, + required List items, + double? shipping, + double? tax, + String? coupon, + }) async { + try { + await _analytics.logPurchase( + currency: 'VND', + transactionId: orderId, + value: value, + items: items, + shipping: shipping, + tax: tax, + coupon: coupon, + ); + debugPrint('πŸ“Š Analytics: purchase - Order $orderId'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + // ============================================================================ + // Search & Discovery Events + // ============================================================================ + + /// Log search event + static Future logSearch({ + required String searchTerm, + }) async { + try { + await _analytics.logSearch(searchTerm: searchTerm); + debugPrint('πŸ“Š Analytics: search - $searchTerm'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log select item event - when user taps on a product in list + static Future logSelectItem({ + required String productId, + required String productName, + String? listName, + }) async { + try { + await _analytics.logSelectItem( + itemListName: listName, + items: [ + AnalyticsEventItem( + itemId: productId, + itemName: productName, + ), + ], + ); + debugPrint('πŸ“Š Analytics: select_item - $productName'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + // ============================================================================ + // Loyalty & Rewards Events + // ============================================================================ + + /// Log earn points event + static Future logEarnPoints({ + required int points, + required String source, + }) async { + try { + await _analytics.logEarnVirtualCurrency( + virtualCurrencyName: 'loyalty_points', + value: points.toDouble(), + ); + debugPrint('πŸ“Š Analytics: earn_points - $points from $source'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log spend points event - when user redeems points + static Future logSpendPoints({ + required int points, + required String itemName, + }) async { + try { + await _analytics.logSpendVirtualCurrency( + virtualCurrencyName: 'loyalty_points', + value: points.toDouble(), + itemName: itemName, + ); + debugPrint('πŸ“Š Analytics: spend_points - $points for $itemName'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + // ============================================================================ + // User Events + // ============================================================================ + + /// Log login event + static Future logLogin({ + String? method, + }) async { + try { + await _analytics.logLogin(loginMethod: method ?? 'phone'); + debugPrint('πŸ“Š Analytics: login - $method'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log sign up event + static Future logSignUp({ + String? method, + }) async { + try { + await _analytics.logSignUp(signUpMethod: method ?? 'phone'); + debugPrint('πŸ“Š Analytics: sign_up - $method'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Log share event + static Future logShare({ + required String contentType, + required String itemId, + String? method, + }) async { + try { + await _analytics.logShare( + contentType: contentType, + itemId: itemId, + method: method ?? 'unknown', + ); + debugPrint('πŸ“Š Analytics: share - $contentType $itemId'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + // ============================================================================ + // Custom Events + // ============================================================================ + + /// Log custom event + static Future logEvent({ + required String name, + Map? parameters, + }) async { + try { + await _analytics.logEvent(name: name, parameters: parameters); + debugPrint('πŸ“Š Analytics: $name'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Set user ID for analytics + static Future setUserId(String? userId) async { + try { + await _analytics.setUserId(id: userId); + debugPrint('πŸ“Š Analytics: setUserId - $userId'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } + + /// Set user property + static Future setUserProperty({ + required String name, + required String? value, + }) async { + try { + await _analytics.setUserProperty(name: name, value: value); + debugPrint('πŸ“Š Analytics: setUserProperty - $name: $value'); + } catch (e) { + debugPrint('πŸ“Š Analytics error: $e'); + } + } } diff --git a/lib/features/account/presentation/providers/user_info_provider.g.dart b/lib/features/account/presentation/providers/user_info_provider.g.dart index 87b8850..c130d08 100644 --- a/lib/features/account/presentation/providers/user_info_provider.g.dart +++ b/lib/features/account/presentation/providers/user_info_provider.g.dart @@ -160,7 +160,7 @@ String _$getUserInfoUseCaseHash() => /// /// userInfoAsync.when( /// data: (userInfo) => Text(userInfo.fullName), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// @@ -184,7 +184,7 @@ const userInfoProvider = UserInfoProvider._(); /// /// userInfoAsync.when( /// data: (userInfo) => Text(userInfo.fullName), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// @@ -206,7 +206,7 @@ final class UserInfoProvider /// /// userInfoAsync.when( /// data: (userInfo) => Text(userInfo.fullName), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// @@ -247,7 +247,7 @@ String _$userInfoHash() => r'ed28fdf0213dfd616592b9735cd291f147867047'; /// /// userInfoAsync.when( /// data: (userInfo) => Text(userInfo.fullName), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// diff --git a/lib/features/home/presentation/providers/member_card_provider.g.dart b/lib/features/home/presentation/providers/member_card_provider.g.dart index f071827..ab7109f 100644 --- a/lib/features/home/presentation/providers/member_card_provider.g.dart +++ b/lib/features/home/presentation/providers/member_card_provider.g.dart @@ -20,7 +20,7 @@ part of 'member_card_provider.dart'; /// /// memberCardAsync.when( /// data: (memberCard) => MemberCardWidget(memberCard: memberCard), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -40,7 +40,7 @@ const memberCardProvider = MemberCardNotifierProvider._(); /// /// memberCardAsync.when( /// data: (memberCard) => MemberCardWidget(memberCard: memberCard), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -58,7 +58,7 @@ final class MemberCardNotifierProvider /// /// memberCardAsync.when( /// data: (memberCard) => MemberCardWidget(memberCard: memberCard), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -96,7 +96,7 @@ String _$memberCardNotifierHash() => /// /// memberCardAsync.when( /// data: (memberCard) => MemberCardWidget(memberCard: memberCard), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` diff --git a/lib/features/home/presentation/providers/promotions_provider.g.dart b/lib/features/home/presentation/providers/promotions_provider.g.dart index ea8770c..35480de 100644 --- a/lib/features/home/presentation/providers/promotions_provider.g.dart +++ b/lib/features/home/presentation/providers/promotions_provider.g.dart @@ -21,7 +21,7 @@ part of 'promotions_provider.dart'; /// /// promotionsAsync.when( /// data: (promotions) => PromotionSlider(promotions: promotions), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -42,7 +42,7 @@ const promotionsProvider = PromotionsProvider._(); /// /// promotionsAsync.when( /// data: (promotions) => PromotionSlider(promotions: promotions), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -68,7 +68,7 @@ final class PromotionsProvider /// /// promotionsAsync.when( /// data: (promotions) => PromotionSlider(promotions: promotions), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` diff --git a/lib/features/products/presentation/pages/products_page.dart b/lib/features/products/presentation/pages/products_page.dart index 364be4b..8676049 100644 --- a/lib/features/products/presentation/pages/products_page.dart +++ b/lib/features/products/presentation/pages/products_page.dart @@ -13,6 +13,7 @@ import 'package:worker/core/constants/ui_constants.dart'; import 'package:worker/core/router/app_router.dart'; import 'package:worker/core/theme/colors.dart'; import 'package:worker/features/cart/presentation/providers/cart_provider.dart'; +import 'package:worker/features/products/presentation/providers/product_filters_provider.dart'; import 'package:worker/features/products/presentation/providers/products_provider.dart'; import 'package:worker/features/products/presentation/widgets/brand_filter_chips.dart'; import 'package:worker/features/products/presentation/widgets/product_filter_drawer.dart'; @@ -100,6 +101,8 @@ class ProductsPage extends ConsumerWidget { ), child: IconButton( onPressed: () { + // Sync pending filters with applied filters before opening drawer + ref.read(productFiltersProvider.notifier).syncWithApplied(); // Open filter drawer from right Scaffold.of(scaffoldContext).openEndDrawer(); }, diff --git a/lib/features/products/presentation/providers/product_filter_options_provider.g.dart b/lib/features/products/presentation/providers/product_filter_options_provider.g.dart index da5424f..f73ae37 100644 --- a/lib/features/products/presentation/providers/product_filter_options_provider.g.dart +++ b/lib/features/products/presentation/providers/product_filter_options_provider.g.dart @@ -24,7 +24,7 @@ part of 'product_filter_options_provider.dart'; /// /// filterOptionsAsync.when( /// data: (options) => ProductFilterDrawer(options: options), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -48,7 +48,7 @@ const productFilterOptionsProvider = ProductFilterOptionsProvider._(); /// /// filterOptionsAsync.when( /// data: (options) => ProductFilterDrawer(options: options), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -79,7 +79,7 @@ final class ProductFilterOptionsProvider /// /// filterOptionsAsync.when( /// data: (options) => ProductFilterDrawer(options: options), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` diff --git a/lib/features/products/presentation/providers/product_filters_provider.dart b/lib/features/products/presentation/providers/product_filters_provider.dart index 43e80dd..b774ef5 100644 --- a/lib/features/products/presentation/providers/product_filters_provider.dart +++ b/lib/features/products/presentation/providers/product_filters_provider.dart @@ -1,6 +1,8 @@ /// Provider: Product Filters State /// -/// Manages product filter selections. +/// Manages product filter selections with separate pending and applied states. +/// Pending filters: Updated on every checkbox toggle (no API call) +/// Applied filters: Only updated when Apply button is pressed (triggers API) library; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -54,7 +56,10 @@ class ProductFiltersState { } } -/// Product Filters Notifier +/// Product Filters Notifier (Pending Filters - for UI selection) +/// +/// This provider stores the PENDING filter selections in the drawer. +/// Changes here do NOT trigger API calls. class ProductFiltersNotifier extends Notifier { @override ProductFiltersState build() => const ProductFiltersState(); @@ -114,19 +119,52 @@ class ProductFiltersNotifier extends Notifier { state = state.copyWith(brands: newSet); } - /// Reset all filters + /// Reset all filters (both pending and applied) void reset() { state = const ProductFiltersState(); + // Also reset applied filters + ref.read(appliedProductFiltersProvider.notifier).reset(); } - /// Apply filters (placeholder for future implementation) + /// Apply filters - copies pending state to applied state + /// This is the ONLY action that triggers API calls void apply() { - // TODO: Trigger products provider refresh with filters + ref.read(appliedProductFiltersProvider.notifier).applyFilters(state); + } + + /// Sync pending state with applied state (when opening drawer) + void syncWithApplied() { + state = ref.read(appliedProductFiltersProvider); } } -/// Product Filters Provider +/// Applied Product Filters Notifier (Triggers API calls) +/// +/// This provider stores the APPLIED filter state. +/// The products provider watches THIS provider, not the pending one. +class AppliedProductFiltersNotifier extends Notifier { + @override + ProductFiltersState build() => const ProductFiltersState(); + + /// Apply filters from pending state + void applyFilters(ProductFiltersState filters) { + state = filters; + } + + /// Reset applied filters + void reset() { + state = const ProductFiltersState(); + } +} + +/// Product Filters Provider (Pending - for drawer UI) final productFiltersProvider = NotifierProvider( ProductFiltersNotifier.new, ); + +/// Applied Product Filters Provider (Triggers API) +final appliedProductFiltersProvider = + NotifierProvider( + AppliedProductFiltersNotifier.new, +); diff --git a/lib/features/products/presentation/providers/products_provider.dart b/lib/features/products/presentation/providers/products_provider.dart index 710c4bd..2ebf8d9 100644 --- a/lib/features/products/presentation/providers/products_provider.dart +++ b/lib/features/products/presentation/providers/products_provider.dart @@ -81,7 +81,8 @@ class Products extends _$Products { // Watch dependencies (triggers rebuild when they change) final searchQuery = ref.watch(searchQueryProvider); - final filters = ref.watch(productFiltersProvider); + // Watch APPLIED filters, not pending filters (API only called on Apply) + final filters = ref.watch(appliedProductFiltersProvider); // Get repository with injected data sources final repository = await ref.watch(productsRepositoryProvider.future); @@ -148,7 +149,8 @@ class Products extends _$Products { // Read dependencies to get current filters (use read, not watch) final searchQuery = ref.read(searchQueryProvider); - final filters = ref.read(productFiltersProvider); + // Read APPLIED filters, not pending filters + final filters = ref.read(appliedProductFiltersProvider); // Get repository final repository = await ref.read(productsRepositoryProvider.future); diff --git a/lib/features/products/presentation/providers/products_provider.g.dart b/lib/features/products/presentation/providers/products_provider.g.dart index dcce576..eedd83b 100644 --- a/lib/features/products/presentation/providers/products_provider.g.dart +++ b/lib/features/products/presentation/providers/products_provider.g.dart @@ -167,7 +167,7 @@ String _$productsRepositoryHash() => /// /// productsAsync.when( /// data: (products) => ProductGrid(products: products), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -187,7 +187,7 @@ const productsProvider = ProductsProvider._(); /// /// productsAsync.when( /// data: (products) => ProductGrid(products: products), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -205,7 +205,7 @@ final class ProductsProvider /// /// productsAsync.when( /// data: (products) => ProductGrid(products: products), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -228,7 +228,7 @@ final class ProductsProvider Products create() => Products(); } -String _$productsHash() => r'a4f416712cdbf2e633622c65b1fdc95686e31fa4'; +String _$productsHash() => r'502af6c2e9012a619c15fd04bfe778045739e247'; /// Products Provider /// @@ -242,7 +242,7 @@ String _$productsHash() => r'a4f416712cdbf2e633622c65b1fdc95686e31fa4'; /// /// productsAsync.when( /// data: (products) => ProductGrid(products: products), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -333,7 +333,7 @@ String _$allProductsHash() => r'402d7c6e8d119c7c7eab5e696fb8163831259def'; /// /// productAsync.when( /// data: (product) => ProductDetailView(product: product), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -352,7 +352,7 @@ const productDetailProvider = ProductDetailFamily._(); /// /// productAsync.when( /// data: (product) => ProductDetailView(product: product), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -371,7 +371,7 @@ final class ProductDetailProvider /// /// productAsync.when( /// data: (product) => ProductDetailView(product: product), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -431,7 +431,7 @@ String _$productDetailHash() => r'ca219f1451f518c84ca1832aacb3c83920f4bfd2'; /// /// productAsync.when( /// data: (product) => ProductDetailView(product: product), -/// loading: () => CircularProgressIndicator(), +/// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` @@ -458,7 +458,7 @@ final class ProductDetailFamily extends $Family /// /// productAsync.when( /// data: (product) => ProductDetailView(product: product), - /// loading: () => CircularProgressIndicator(), + /// loading: () => const CustomLoadingIndicator(), /// error: (error, stack) => ErrorWidget(error), /// ); /// ``` diff --git a/lib/features/products/presentation/widgets/brand_filter_chips.dart b/lib/features/products/presentation/widgets/brand_filter_chips.dart index 850d5ed..929e2cb 100644 --- a/lib/features/products/presentation/widgets/brand_filter_chips.dart +++ b/lib/features/products/presentation/widgets/brand_filter_chips.dart @@ -13,15 +13,16 @@ import 'package:worker/features/products/presentation/providers/product_filters_ /// Brand Filter Chips Widget /// /// Displays brands as horizontally scrolling chips. -/// Synced with filter drawer - both use productFiltersProvider.brands. -/// Chips are single-select (tapping a brand clears others and sets just that one). +/// Watches appliedProductFiltersProvider to show currently active filters. +/// Tapping a chip directly applies the filter (triggers API call immediately). class BrandFilterChips extends ConsumerWidget { const BrandFilterChips({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final colorScheme = Theme.of(context).colorScheme; - final filtersState = ref.watch(productFiltersProvider); + // Watch APPLIED filters to show current active state + final appliedFilters = ref.watch(appliedProductFiltersProvider); final filterOptionsAsync = ref.watch(productFilterOptionsProvider); return filterOptionsAsync.when( @@ -46,9 +47,9 @@ class BrandFilterChips extends ConsumerWidget { // "TαΊ₯t cαΊ£" is selected if no brands are selected // A brand chip is selected if it's the ONLY brand selected final isSelected = brand.value == 'all' - ? filtersState.brands.isEmpty - : (filtersState.brands.length == 1 && - filtersState.brands.contains(brand.value)); + ? appliedFilters.brands.isEmpty + : (appliedFilters.brands.length == 1 && + appliedFilters.brands.contains(brand.value)); return FilterChip( label: Text( @@ -62,27 +63,22 @@ class BrandFilterChips extends ConsumerWidget { selected: isSelected, onSelected: (selected) { if (selected) { - final notifier = ref.read(productFiltersProvider.notifier); + // Create new filter state with only the selected brand + ProductFiltersState newFilters; if (brand.value == 'all') { - // Clear all brand filters - // Reset all brands by setting to empty set - final currentBrands = List.from(filtersState.brands); - for (final b in currentBrands) { - notifier.toggleBrand(b); // Toggle off each brand - } + // Clear brand filter, keep other filters + newFilters = appliedFilters.copyWith(brands: {}); } else { - // Single-select: clear all other brands and set only this one - final currentBrands = List.from(filtersState.brands); - - // First, clear all existing brands - for (final b in currentBrands) { - notifier.toggleBrand(b); - } - - // Then add the selected brand - notifier.toggleBrand(brand.value); + // Set only this brand, keep other filters + newFilters = appliedFilters.copyWith(brands: {brand.value}); } + + // Apply directly to trigger API call + ref.read(appliedProductFiltersProvider.notifier).applyFilters(newFilters); + + // Also sync pending filters with applied + ref.read(productFiltersProvider.notifier).syncWithApplied(); } }, backgroundColor: colorScheme.surface,