/// App Router Configuration /// /// Centralized routing configuration using go_router. /// Defines all routes, navigation guards, and deep linking. library; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:worker/features/account/domain/entities/address.dart'; import 'package:worker/features/account/presentation/pages/address_form_page.dart'; import 'package:worker/features/account/presentation/pages/addresses_page.dart'; import 'package:worker/features/account/presentation/pages/change_password_page.dart'; import 'package:worker/features/account/presentation/pages/profile_edit_page.dart'; import 'package:worker/features/auth/presentation/providers/auth_provider.dart'; import 'package:worker/features/auth/domain/entities/business_unit.dart'; import 'package:worker/features/auth/presentation/pages/business_unit_selection_page.dart'; import 'package:worker/features/auth/presentation/pages/forgot_password_page.dart'; import 'package:worker/features/auth/presentation/pages/login_page.dart'; import 'package:worker/features/auth/presentation/pages/otp_verification_page.dart'; import 'package:worker/features/auth/presentation/pages/register_page.dart'; import 'package:worker/features/auth/presentation/pages/splash_page.dart'; import 'package:worker/features/cart/presentation/pages/cart_page.dart'; import 'package:worker/features/cart/presentation/pages/checkout_page.dart'; import 'package:worker/features/chat/presentation/pages/chat_list_page.dart'; import 'package:worker/features/favorites/presentation/pages/favorites_page.dart'; import 'package:worker/features/loyalty/presentation/pages/loyalty_page.dart'; import 'package:worker/features/loyalty/presentation/pages/points_history_page.dart'; import 'package:worker/features/loyalty/presentation/pages/rewards_page.dart'; import 'package:worker/features/main/presentation/pages/main_scaffold.dart'; import 'package:worker/features/news/presentation/pages/news_detail_page.dart'; import 'package:worker/features/news/presentation/pages/news_list_page.dart'; import 'package:worker/features/orders/presentation/pages/order_detail_page.dart'; import 'package:worker/features/orders/presentation/pages/orders_page.dart'; import 'package:worker/features/orders/presentation/pages/payment_detail_page.dart'; import 'package:worker/features/orders/presentation/pages/payment_qr_page.dart'; import 'package:worker/features/orders/presentation/pages/payments_page.dart'; import 'package:worker/features/price_policy/price_policy.dart'; import 'package:worker/features/products/presentation/pages/product_detail_page.dart'; import 'package:worker/features/products/presentation/pages/products_page.dart'; import 'package:worker/features/products/presentation/pages/write_review_page.dart'; import 'package:worker/features/promotions/presentation/pages/promotion_detail_page.dart'; import 'package:worker/features/quotes/presentation/pages/quotes_page.dart'; import 'package:worker/features/showrooms/presentation/pages/design_request_create_page.dart'; import 'package:worker/features/showrooms/presentation/pages/design_request_detail_page.dart'; import 'package:worker/features/showrooms/presentation/pages/model_houses_page.dart'; /// Router Provider /// /// Provides GoRouter instance with auth state management final routerProvider = Provider((ref) { final authState = ref.watch(authProvider); return GoRouter( // Initial route - start with splash screen initialLocation: RouteNames.splash, // Redirect based on auth state redirect: (context, state) { final isLoading = authState.isLoading; final isLoggedIn = authState.value != null; final isOnSplashPage = state.matchedLocation == RouteNames.splash; final isOnLoginPage = state.matchedLocation == RouteNames.login; final isOnForgotPasswordPage = state.matchedLocation == RouteNames.forgotPassword; final isOnRegisterPage = state.matchedLocation == RouteNames.register; final isOnBusinessUnitPage = state.matchedLocation == RouteNames.businessUnitSelection; final isOnOtpPage = state.matchedLocation == RouteNames.otpVerification; final isOnAuthPage = isOnLoginPage || isOnForgotPasswordPage || isOnRegisterPage || isOnBusinessUnitPage || isOnOtpPage; // While loading auth state, show splash screen if (isLoading) { return RouteNames.splash; } // After loading, redirect from splash to appropriate page if (isOnSplashPage && !isLoading) { return isLoggedIn ? RouteNames.home : RouteNames.login; } // If not logged in and not on auth/splash pages, redirect to login if (!isLoggedIn && !isOnAuthPage && !isOnSplashPage) { return RouteNames.login; } // If logged in and on login page, redirect to home if (isLoggedIn && isOnLoginPage) { return RouteNames.home; } // No redirect needed return null; }, // Route definitions routes: [ // Splash Screen Route GoRoute( path: RouteNames.splash, name: RouteNames.splash, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const SplashPage()), ), // Authentication Routes GoRoute( path: RouteNames.login, name: RouteNames.login, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const LoginPage()), ), GoRoute( path: RouteNames.forgotPassword, name: RouteNames.forgotPassword, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ForgotPasswordPage()), ), GoRoute( path: RouteNames.otpVerification, name: RouteNames.otpVerification, pageBuilder: (context, state) { final phoneNumber = state.extra as String? ?? ''; return MaterialPage( key: state.pageKey, child: OtpVerificationPage(phoneNumber: phoneNumber), ); }, ), GoRoute( path: RouteNames.register, name: RouteNames.register, pageBuilder: (context, state) { final extra = state.extra as Map?; return MaterialPage( key: state.pageKey, child: RegisterPage( selectedBusinessUnit: extra?['businessUnit'] as BusinessUnit?, ), ); }, ), GoRoute( path: RouteNames.businessUnitSelection, name: RouteNames.businessUnitSelection, pageBuilder: (context, state) { final extra = state.extra as Map?; return MaterialPage( key: state.pageKey, child: BusinessUnitSelectionPage( businessUnits: extra?['businessUnits'] as List?, isRegistrationFlow: (extra?['isRegistrationFlow'] as bool?) ?? false, ), ); }, ), // Main Route (with bottom navigation) GoRoute( path: RouteNames.home, name: RouteNames.home, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const MainScaffold()), ), // Products Route (full screen, no bottom nav) GoRoute( path: RouteNames.products, name: RouteNames.products, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ProductsPage()), ), // Product Detail Route GoRoute( path: RouteNames.productDetail, name: RouteNames.productDetail, pageBuilder: (context, state) { final productId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: ProductDetailPage(productId: productId ?? ''), ); }, routes: [ // Write Review Route (nested under product detail) GoRoute( path: 'write-review', name: RouteNames.writeReview, pageBuilder: (context, state) { final productId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: WriteReviewPage(productId: productId ?? ''), ); }, ), ], ), // Promotion Detail Route GoRoute( path: RouteNames.promotionDetail, name: RouteNames.promotionDetail, pageBuilder: (context, state) { final promotionId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: PromotionDetailPage(promotionId: promotionId), ); }, ), // Cart Route GoRoute( path: RouteNames.cart, name: RouteNames.cart, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const CartPage()), ), // Checkout Route GoRoute( path: RouteNames.checkout, name: RouteNames.checkout, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: CheckoutPage( checkoutData: state.extra as Map?, ), ), ), // Favorites Route GoRoute( path: RouteNames.favorites, name: RouteNames.favorites, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const FavoritesPage()), ), // Loyalty Route GoRoute( path: RouteNames.loyalty, name: RouteNames.loyalty, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const LoyaltyPage()), ), // Loyalty Rewards Route GoRoute( path: '/loyalty/rewards', name: 'loyalty_rewards', pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const RewardsPage()), ), // Points History Route GoRoute( path: RouteNames.pointsHistory, name: 'loyalty_points_history', pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const PointsHistoryPage()), ), // Orders Route GoRoute( path: RouteNames.orders, name: RouteNames.orders, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const OrdersPage()), ), // Order Detail Route GoRoute( path: RouteNames.orderDetail, name: RouteNames.orderDetail, pageBuilder: (context, state) { final orderId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: OrderDetailPage(orderId: orderId ?? ''), ); }, ), // Payments Route GoRoute( path: RouteNames.payments, name: RouteNames.payments, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const PaymentsPage()), ), // Payment Detail Route GoRoute( path: RouteNames.paymentDetail, name: RouteNames.paymentDetail, pageBuilder: (context, state) { final invoiceId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: PaymentDetailPage(invoiceId: invoiceId ?? ''), ); }, ), // Payment QR Route GoRoute( path: RouteNames.paymentQr, name: RouteNames.paymentQr, pageBuilder: (context, state) { final orderId = state.uri.queryParameters['orderId'] ?? ''; final amountStr = state.uri.queryParameters['amount'] ?? '0'; final amount = double.tryParse(amountStr) ?? 0.0; return MaterialPage( key: state.pageKey, child: PaymentQrPage(orderId: orderId, amount: amount), ); }, ), // Quotes Route GoRoute( path: RouteNames.quotes, name: RouteNames.quotes, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const QuotesPage()), ), // Price Policy Route GoRoute( path: RouteNames.pricePolicy, name: RouteNames.pricePolicy, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const PricePolicyPage()), ), // News Route GoRoute( path: RouteNames.news, name: RouteNames.news, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const NewsListPage()), ), // News Detail Route GoRoute( path: RouteNames.newsDetail, name: RouteNames.newsDetail, pageBuilder: (context, state) { final articleId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: NewsDetailPage(articleId: articleId ?? ''), ); }, ), // Profile Edit Route GoRoute( path: RouteNames.profile, name: RouteNames.profile, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ProfileEditPage()), ), // Addresses Route GoRoute( path: RouteNames.addresses, name: RouteNames.addresses, pageBuilder: (context, state) { final extra = state.extra as Map?; return MaterialPage( key: state.pageKey, child: AddressesPage(extra: extra), ); }, ), // Address Form Route (Create/Edit) GoRoute( path: RouteNames.addressForm, name: RouteNames.addressForm, pageBuilder: (context, state) { final address = state.extra as Address?; return MaterialPage( key: state.pageKey, child: AddressFormPage(address: address), ); }, ), // Change Password Route GoRoute( path: RouteNames.changePassword, name: RouteNames.changePassword, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ChangePasswordPage()), ), // Chat List Route GoRoute( path: RouteNames.chat, name: RouteNames.chat, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ChatListPage()), ), // Model Houses Route GoRoute( path: RouteNames.modelHouses, name: RouteNames.modelHouses, pageBuilder: (context, state) => MaterialPage(key: state.pageKey, child: const ModelHousesPage()), ), // Design Request Create Route GoRoute( path: RouteNames.designRequestCreate, name: RouteNames.designRequestCreate, pageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: const DesignRequestCreatePage(), ), ), // Design Request Detail Route GoRoute( path: RouteNames.designRequestDetail, name: RouteNames.designRequestDetail, pageBuilder: (context, state) { final requestId = state.pathParameters['id']; return MaterialPage( key: state.pageKey, child: DesignRequestDetailPage(requestId: requestId ?? 'YC001'), ); }, ), // TODO: Add more routes as features are implemented ], // Error page for unknown routes errorPageBuilder: (context, state) => MaterialPage( key: state.pageKey, child: Scaffold( appBar: AppBar(title: const Text('Không tìm thấy trang')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 64, color: Colors.red), const SizedBox(height: 16), const Text( 'Trang không tồn tại', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Text( state.uri.toString(), style: const TextStyle(color: Colors.grey), ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: () => context.go(RouteNames.home), icon: const Icon(Icons.home), label: const Text('Về trang chủ'), ), ], ), ), ), ), // Debug logging (disable in production) debugLogDiagnostics: true, ); }); /// Route Names /// /// Centralized route name constants for type-safe navigation. /// Use these constants instead of hardcoded strings. /// /// Example: /// ```dart /// context.go(RouteNames.home); /// context.push(RouteNames.products); /// ``` class RouteNames { // Private constructor to prevent instantiation RouteNames._(); // Main Routes static const String home = '/'; static const String products = '/products'; static const String productDetail = '/products/:id'; static const String writeReview = 'write-review'; static const String cart = '/cart'; static const String favorites = '/favorites'; static const String checkout = '/checkout'; static const String orderSuccess = '/order-success'; // Loyalty Routes static const String loyalty = '/loyalty'; static const String rewards = '/loyalty/rewards'; static const String pointsHistory = '/loyalty/points-history'; static const String myGifts = '/loyalty/gifts'; static const String referral = '/loyalty/referral'; // Orders & Payments Routes static const String orders = '/orders'; static const String orderDetail = '/orders/:id'; static const String payments = '/payments'; static const String paymentDetail = '/payments/:id'; static const String paymentQr = '/payment-qr'; // Projects & Quotes Routes static const String projects = '/projects'; static const String projectDetail = '/projects/:id'; static const String projectCreate = '/projects/create'; static const String quotes = '/quotes'; static const String quoteDetail = '/quotes/:id'; static const String quoteCreate = '/quotes/create'; // Account Routes static const String account = '/account'; static const String profile = '/account/profile'; static const String addresses = '/account/addresses'; static const String addressForm = '/account/addresses/form'; static const String changePassword = '/account/change-password'; static const String settings = '/account/settings'; // Promotions & Notifications Routes static const String promotions = '/promotions'; static const String promotionDetail = '/promotions/:id'; static const String notifications = '/notifications'; // Price Policy Route static const String pricePolicy = '/price-policy'; // News Route static const String news = '/news'; static const String newsDetail = '/news/:id'; // Chat Route static const String chat = '/chat'; // Model Houses & Design Requests Routes static const String modelHouses = '/model-houses'; static const String designRequestCreate = '/model-houses/design-request/create'; static const String designRequestDetail = '/model-houses/design-request/:id'; // Authentication Routes static const String splash = '/splash'; static const String login = '/login'; static const String forgotPassword = '/forgot-password'; static const String otpVerification = '/otp-verification'; static const String register = '/register'; static const String businessUnitSelection = '/business-unit-selection'; } /// Route Extensions /// /// Helper extensions for common navigation patterns. extension GoRouterExtension on BuildContext { /// Navigate to login page void goLogin() => go(RouteNames.login); /// Navigate to register page void goRegister() => go(RouteNames.register); /// Navigate to home page void goHome() => go(RouteNames.home); /// Navigate to products page void goProducts() => go(RouteNames.products); /// Navigate to cart page void goCart() => go(RouteNames.cart); /// Navigate to favorites page void goFavorites() => go(RouteNames.favorites); /// Navigate to loyalty page void goLoyalty() => go(RouteNames.loyalty); /// Navigate to orders page void goOrders() => go(RouteNames.orders); /// Navigate to projects page void goProjects() => go(RouteNames.projects); /// Navigate to account page void goAccount() => go(RouteNames.account); /// Navigate to promotions page void goPromotions() => go(RouteNames.promotions); /// Navigate to notifications page void goNotifications() => go(RouteNames.notifications); /// Navigate to chat page void goChat() => go(RouteNames.chat); }