# App Router Documentation Complete navigation setup for the warehouse management application using GoRouter. ## Overview The app router implements authentication-based navigation with proper redirect logic: - **Unauthenticated users** are redirected to `/login` - **Authenticated users** on `/login` are redirected to `/warehouses` - Type-safe parameter passing between routes - Integration with SecureStorage for authentication checks ## App Flow ``` Login → Warehouses → Operations → Products ``` 1. **Login**: User authenticates and token is stored 2. **Warehouses**: User selects a warehouse 3. **Operations**: User chooses Import or Export 4. **Products**: Display products based on warehouse and operation ## Routes ### `/login` - Login Page - **Name**: `login` - **Purpose**: User authentication - **Parameters**: None - **Redirect**: If authenticated → `/warehouses` ### `/warehouses` - Warehouse Selection Page - **Name**: `warehouses` - **Purpose**: Display list of warehouses - **Parameters**: None - **Protected**: Requires authentication ### `/operations` - Operation Selection Page - **Name**: `operations` - **Purpose**: Choose Import or Export operation - **Parameters**: - `extra`: `WarehouseEntity` object - **Protected**: Requires authentication - **Validation**: Redirects to `/warehouses` if warehouse data is missing ### `/products` - Products List Page - **Name**: `products` - **Purpose**: Display products for warehouse and operation - **Parameters**: - `extra`: `Map` containing: - `warehouse`: `WarehouseEntity` object - `warehouseName`: `String` - `operationType`: `String` ('import' or 'export') - **Protected**: Requires authentication - **Validation**: Redirects to `/warehouses` if parameters are invalid ## Usage Examples ### Basic Navigation ```dart import 'package:go_router/go_router.dart'; // Navigate to login context.go('/login'); // Navigate to warehouses context.go('/warehouses'); ``` ### Navigation with Extension Methods ```dart import 'package:minhthu/core/router/app_router.dart'; // Navigate to login context.goToLogin(); // Navigate to warehouses context.goToWarehouses(); // Navigate to operations with warehouse context.goToOperations(warehouse); // Navigate to products with warehouse and operation type context.goToProducts( warehouse: warehouse, operationType: 'import', ); // Go back context.goBack(); ``` ### Named Route Navigation ```dart // Using named routes context.goToLoginNamed(); context.goToWarehousesNamed(); context.goToOperationsNamed(warehouse); context.goToProductsNamed( warehouse: warehouse, operationType: 'export', ); ``` ## Integration with Warehouse Selection ### Example: Navigate from Warehouse to Operations ```dart import 'package:flutter/material.dart'; import 'package:minhthu/core/router/app_router.dart'; import 'package:minhthu/features/warehouse/domain/entities/warehouse_entity.dart'; class WarehouseCard extends StatelessWidget { final WarehouseEntity warehouse; const WarehouseCard({required this.warehouse}); @override Widget build(BuildContext context) { return Card( child: ListTile( title: Text(warehouse.name), subtitle: Text('Code: ${warehouse.code}'), trailing: Icon(Icons.arrow_forward), onTap: () { // Navigate to operations page context.goToOperations(warehouse); }, ), ); } } ``` ### Example: Navigate from Operations to Products ```dart import 'package:flutter/material.dart'; import 'package:minhthu/core/router/app_router.dart'; import 'package:minhthu/features/warehouse/domain/entities/warehouse_entity.dart'; class OperationButton extends StatelessWidget { final WarehouseEntity warehouse; final String operationType; const OperationButton({ required this.warehouse, required this.operationType, }); @override Widget build(BuildContext context) { return ElevatedButton( onPressed: () { // Navigate to products page context.goToProducts( warehouse: warehouse, operationType: operationType, ); }, child: Text(operationType == 'import' ? 'Import Products' : 'Export Products'), ); } } ``` ## Authentication Integration The router automatically checks authentication status on every navigation: ```dart // In app_router.dart Future _handleRedirect( BuildContext context, GoRouterState state, ) async { // Check if user has access token final isAuthenticated = await secureStorage.isAuthenticated(); final isOnLoginPage = state.matchedLocation == '/login'; // Redirect logic if (!isAuthenticated && !isOnLoginPage) { return '/login'; // Redirect to login } if (isAuthenticated && isOnLoginPage) { return '/warehouses'; // Redirect to warehouses } return null; // Allow navigation } ``` ### SecureStorage Integration The router uses `SecureStorage` to check authentication: ```dart // Check if authenticated final isAuthenticated = await secureStorage.isAuthenticated(); // This checks if access token exists Future isAuthenticated() async { final token = await getAccessToken(); return token != null && token.isNotEmpty; } ``` ## Reactive Navigation The router automatically reacts to authentication state changes: ```dart class GoRouterRefreshStream extends ChangeNotifier { final Ref ref; GoRouterRefreshStream(this.ref) { // Listen to auth state changes ref.listen( authProvider, // From auth_dependency_injection.dart (_, __) => notifyListeners(), ); } } ``` When authentication state changes (login/logout), the router: 1. Receives notification 2. Re-evaluates redirect logic 3. Automatically redirects to appropriate page ## Error Handling ### Missing Parameters If route parameters are missing, the user is redirected: ```dart GoRoute( path: '/operations', builder: (context, state) { final warehouse = state.extra as WarehouseEntity?; if (warehouse == null) { // Show error and redirect WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/warehouses'); }); return const _ErrorScreen( message: 'Warehouse data is required', ); } return OperationSelectionPage(warehouse: warehouse); }, ), ``` ### Page Not Found Custom 404 error page: ```dart errorBuilder: (context, state) { return Scaffold( appBar: AppBar(title: const Text('Page Not Found')), body: Center( child: Column( children: [ Icon(Icons.error_outline, size: 64), Text('Page "${state.uri.path}" does not exist'), ElevatedButton( onPressed: () => context.go('/login'), child: const Text('Go to Login'), ), ], ), ), ); } ``` ## Setup in main.dart ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:minhthu/core/router/app_router.dart'; import 'package:minhthu/core/theme/app_theme.dart'; void main() { runApp( const ProviderScope( child: MyApp(), ), ); } class MyApp extends ConsumerWidget { const MyApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // Get router from provider final router = ref.watch(appRouterProvider); return MaterialApp.router( title: 'Warehouse Manager', theme: AppTheme.lightTheme, routerConfig: router, ); } } ``` ## Best Practices ### 1. Use Extension Methods Prefer extension methods for type-safe navigation: ```dart // Good context.goToProducts(warehouse: warehouse, operationType: 'import'); // Avoid context.go('/products', extra: {'warehouse': warehouse, 'operationType': 'import'}); ``` ### 2. Validate Parameters Always validate route parameters: ```dart final warehouse = state.extra as WarehouseEntity?; if (warehouse == null) { // Handle error } ``` ### 3. Handle Async Operations Use post-frame callbacks for navigation in builders: ```dart WidgetsBinding.instance.addPostFrameCallback((_) { context.go('/warehouses'); }); ``` ### 4. Logout Implementation Clear storage and let router handle redirect: ```dart Future logout() async { await ref.read(authProvider.notifier).logout(); // Router will automatically redirect to /login } ``` ## Troubleshooting ### Issue: Redirect loop **Cause**: Authentication check is not working properly **Solution**: Verify SecureStorage has access token ### Issue: Parameters are null **Cause**: Wrong parameter passing format **Solution**: Use extension methods with correct types ### Issue: Navigation doesn't update **Cause**: Auth state changes not triggering refresh **Solution**: Verify GoRouterRefreshStream is listening to authProvider ## Related Files - `/lib/core/router/app_router.dart` - Main router configuration - `/lib/core/storage/secure_storage.dart` - Authentication storage - `/lib/features/auth/di/auth_dependency_injection.dart` - Auth providers - `/lib/features/auth/presentation/pages/login_page.dart` - Login page - `/lib/features/warehouse/presentation/pages/warehouse_selection_page.dart` - Warehouse page - `/lib/features/operation/presentation/pages/operation_selection_page.dart` - Operation page - `/lib/features/products/presentation/pages/products_page.dart` - Products page