From 4cfe0001727dcd9d1ec7e08d842d4a25ac197271 Mon Sep 17 00:00:00 2001 From: Phuoc Nguyen Date: Tue, 9 Dec 2025 16:57:58 +0700 Subject: [PATCH] add logs --- .../auth/presentation/pages/login_page.dart | 1 + .../presentation/pages/register_page.dart | 4 +++ .../presentation/providers/auth_provider.dart | 9 +++++++ .../providers/auth_provider.g.dart | 2 +- .../cart/presentation/pages/cart_page.dart | 26 +++++++++++++++++++ .../presentation/pages/checkout_page.dart | 18 +++++++++++++ .../presentation/pages/rewards_page.dart | 7 +++++ .../pages/order_success_page.dart | 10 +++++++ .../pages/product_detail_page.dart | 9 +++++++ .../providers/search_query_provider.dart | 3 +++ .../providers/search_query_provider.g.dart | 2 +- 11 files changed, 89 insertions(+), 2 deletions(-) diff --git a/lib/features/auth/presentation/pages/login_page.dart b/lib/features/auth/presentation/pages/login_page.dart index f5c010a..cd631ac 100644 --- a/lib/features/auth/presentation/pages/login_page.dart +++ b/lib/features/auth/presentation/pages/login_page.dart @@ -87,6 +87,7 @@ class _LoginPageState extends ConsumerState { ..when( data: (user) { if (user != null && mounted) { + // Analytics (logLogin & setUserId) are handled in auth_provider // Navigate to home on success context.goHome(); } diff --git a/lib/features/auth/presentation/pages/register_page.dart b/lib/features/auth/presentation/pages/register_page.dart index ebf2669..5b98fc2 100644 --- a/lib/features/auth/presentation/pages/register_page.dart +++ b/lib/features/auth/presentation/pages/register_page.dart @@ -26,6 +26,7 @@ import 'package:worker/features/auth/presentation/providers/customer_groups_prov import 'package:worker/features/auth/presentation/providers/session_provider.dart'; import 'package:worker/features/auth/presentation/widgets/phone_input_field.dart'; import 'package:worker/features/auth/presentation/widgets/file_upload_card.dart'; +import 'package:worker/core/services/analytics_service.dart'; /// Registration Page /// @@ -345,6 +346,9 @@ class _RegisterPageState extends ConsumerState { ); if (mounted) { + // Log sign up analytics event + AnalyticsService.logSignUp(method: 'phone'); + // Show success message ScaffoldMessenger.of(context).showSnackBar( const SnackBar( diff --git a/lib/features/auth/presentation/providers/auth_provider.dart b/lib/features/auth/presentation/providers/auth_provider.dart index b5e8ef1..3358705 100644 --- a/lib/features/auth/presentation/providers/auth_provider.dart +++ b/lib/features/auth/presentation/providers/auth_provider.dart @@ -14,6 +14,7 @@ import 'package:worker/core/services/frappe_auth_service.dart'; import 'package:worker/features/auth/data/datasources/auth_local_datasource.dart'; import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart'; import 'package:worker/features/auth/domain/entities/user.dart'; +import 'package:worker/core/services/analytics_service.dart'; part 'auth_provider.g.dart'; @@ -182,6 +183,11 @@ class Auth extends _$Auth { // Save rememberMe preference await _localDataSource.saveRememberMe(rememberMe); + // Set user ID for analytics tracking + await AnalyticsService.setUserId(phoneNumber); + // Log login event + await AnalyticsService.logLogin(method: 'phone'); + // Create and return User entity final now = DateTime.now(); return User( @@ -218,6 +224,9 @@ class Auth extends _$Auth { state = await AsyncValue.guard(() async { final frappeService = await _frappeAuthService; + // Clear user ID from analytics + await AnalyticsService.setUserId(null); + // Clear saved session await _localDataSource.clearSession(); await frappeService.clearSession(); diff --git a/lib/features/auth/presentation/providers/auth_provider.g.dart b/lib/features/auth/presentation/providers/auth_provider.g.dart index 2146fc8..4acab06 100644 --- a/lib/features/auth/presentation/providers/auth_provider.g.dart +++ b/lib/features/auth/presentation/providers/auth_provider.g.dart @@ -272,7 +272,7 @@ final class AuthProvider extends $AsyncNotifierProvider { Auth create() => Auth(); } -String _$authHash() => r'd851980cad7a624f00eba69e19d8a4fee22008e7'; +String _$authHash() => r'f1d856a9a8fc461da111699e3c7ca2af1f2ce7ca'; /// Authentication Provider /// diff --git a/lib/features/cart/presentation/pages/cart_page.dart b/lib/features/cart/presentation/pages/cart_page.dart index a6c1eb7..2f9ce90 100644 --- a/lib/features/cart/presentation/pages/cart_page.dart +++ b/lib/features/cart/presentation/pages/cart_page.dart @@ -17,6 +17,8 @@ import 'package:worker/core/theme/typography.dart'; import 'package:worker/features/cart/presentation/providers/cart_provider.dart'; import 'package:worker/features/cart/presentation/providers/cart_state.dart'; import 'package:worker/features/cart/presentation/widgets/cart_item_widget.dart'; +import 'package:worker/core/services/analytics_service.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; /// Cart Page /// @@ -52,6 +54,19 @@ class _CartPageState extends ConsumerState { final itemCount = cartState.itemCount; final hasSelection = cartState.selectedCount > 0; + // Log view cart analytics event when cart has items + if (cartState.isNotEmpty) { + AnalyticsService.logViewCart( + cartValue: cartState.selectedTotal, + items: cartState.items.map((item) => AnalyticsEventItem( + itemId: item.product.productId, + itemName: item.product.name, + price: item.product.basePrice, + quantity: item.quantity.toInt(), + )).toList(), + ); + } + return PopScope( // Intercept back navigation to sync pending updates onPopInvokedWithResult: (didPop, result) async { @@ -442,6 +457,17 @@ class _CartPageState extends ConsumerState { ), ElevatedButton( onPressed: () { + // Log remove from cart analytics for selected items + for (final item in cartState.items) { + if (cartState.selectedItems[item.product.productId] == true) { + AnalyticsService.logRemoveFromCart( + productId: item.product.productId, + productName: item.product.name, + price: item.product.basePrice, + quantity: item.quantity.toInt(), + ); + } + } ref.read(cartProvider.notifier).deleteSelected(); context.pop(); ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/features/cart/presentation/pages/checkout_page.dart b/lib/features/cart/presentation/pages/checkout_page.dart index 33d2440..456162d 100644 --- a/lib/features/cart/presentation/pages/checkout_page.dart +++ b/lib/features/cart/presentation/pages/checkout_page.dart @@ -29,6 +29,8 @@ import 'package:worker/features/cart/presentation/widgets/payment_method_section import 'package:worker/features/cart/presentation/widgets/price_negotiation_section.dart'; import 'package:worker/features/orders/presentation/providers/order_status_provider.dart'; import 'package:worker/features/orders/presentation/providers/payment_terms_provider.dart'; +import 'package:worker/core/services/analytics_service.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; /// Checkout Page /// @@ -104,6 +106,22 @@ class CheckoutPage extends HookConsumerWidget { final total = subtotal - memberDiscount + shipping; + // Log begin checkout analytics event + if (cartItemsData.isNotEmpty) { + AnalyticsService.logBeginCheckout( + value: total, + items: cartItemsData.map((itemData) { + final cartItem = itemData as CartItemData; + return AnalyticsEventItem( + itemId: cartItem.product.productId, + itemName: cartItem.product.name, + price: cartItem.product.basePrice, + quantity: cartItem.quantity.toInt(), + ); + }).toList(), + ); + } + return Scaffold( backgroundColor: colorScheme.surfaceContainerLowest, appBar: AppBar( diff --git a/lib/features/loyalty/presentation/pages/rewards_page.dart b/lib/features/loyalty/presentation/pages/rewards_page.dart index ce62fc9..bf11bc7 100644 --- a/lib/features/loyalty/presentation/pages/rewards_page.dart +++ b/lib/features/loyalty/presentation/pages/rewards_page.dart @@ -15,6 +15,7 @@ import 'package:worker/features/loyalty/presentation/providers/gifts_provider.da import 'package:worker/features/loyalty/presentation/providers/loyalty_points_provider.dart'; import 'package:worker/features/loyalty/presentation/widgets/points_balance_card.dart'; import 'package:worker/features/loyalty/presentation/widgets/reward_card.dart'; +import 'package:worker/core/services/analytics_service.dart'; /// Rewards Page /// @@ -441,6 +442,12 @@ class RewardsPage extends ConsumerWidget { WidgetRef ref, GiftCatalog gift, ) { + // Log spend points analytics event + AnalyticsService.logSpendPoints( + points: gift.pointsCost, + itemName: gift.name, + ); + // Deduct points ref.read(loyaltyPointsProvider.notifier).deductPoints(gift.pointsCost); diff --git a/lib/features/orders/presentation/pages/order_success_page.dart b/lib/features/orders/presentation/pages/order_success_page.dart index ca5e109..43f6c03 100644 --- a/lib/features/orders/presentation/pages/order_success_page.dart +++ b/lib/features/orders/presentation/pages/order_success_page.dart @@ -15,6 +15,7 @@ import 'package:intl/intl.dart'; 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/core/services/analytics_service.dart'; /// Order Success Page class OrderSuccessPage extends StatelessWidget { @@ -37,6 +38,15 @@ class OrderSuccessPage extends StatelessWidget { final now = DateTime.now(); final dateFormat = DateFormat('dd/MM/yyyy HH:mm'); + // Log purchase analytics event (only for actual purchases, not negotiations) + if (!isNegotiation && total != null) { + AnalyticsService.logPurchase( + orderId: orderNumber, + value: total!, + items: [], // Items not available in this page + ); + } + return Scaffold( backgroundColor: colorScheme.surface, body: SafeArea( diff --git a/lib/features/products/presentation/pages/product_detail_page.dart b/lib/features/products/presentation/pages/product_detail_page.dart index 00043c3..1ede620 100644 --- a/lib/features/products/presentation/pages/product_detail_page.dart +++ b/lib/features/products/presentation/pages/product_detail_page.dart @@ -239,6 +239,15 @@ class _ProductDetailPageState extends ConsumerState { ), body: productAsync.when( data: (product) { + // Log view item analytics event + AnalyticsService.logViewItem( + productId: product.productId, + productName: product.name, + price: product.basePrice, + brand: product.itemGroupName, + category: product.itemGroupName, + ); + return Column( children: [ // Scrollable content diff --git a/lib/features/products/presentation/providers/search_query_provider.dart b/lib/features/products/presentation/providers/search_query_provider.dart index 1d5f4e5..3910fa9 100644 --- a/lib/features/products/presentation/providers/search_query_provider.dart +++ b/lib/features/products/presentation/providers/search_query_provider.dart @@ -6,6 +6,7 @@ library; import 'dart:async'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:worker/core/services/analytics_service.dart'; part 'search_query_provider.g.dart'; @@ -63,6 +64,8 @@ class SearchQuery extends _$SearchQuery { // Only update if query still meets requirements after delay if (trimmedQuery.length >= 2) { state = trimmedQuery; + // Log search analytics event + AnalyticsService.logSearch(searchTerm: trimmedQuery); } }); } diff --git a/lib/features/products/presentation/providers/search_query_provider.g.dart b/lib/features/products/presentation/providers/search_query_provider.g.dart index 0ae229f..b37f8b9 100644 --- a/lib/features/products/presentation/providers/search_query_provider.g.dart +++ b/lib/features/products/presentation/providers/search_query_provider.g.dart @@ -94,7 +94,7 @@ final class SearchQueryProvider extends $NotifierProvider { } } -String _$searchQueryHash() => r'3a4178c8c220a1016d20887d7bd97cd157f777f8'; +String _$searchQueryHash() => r'62ee3245dca6a43fb276bee72ba6e6d16238e69b'; /// Search Query Provider ///