This commit is contained in:
Phuoc Nguyen
2025-10-23 17:03:58 +07:00
parent 30c245b401
commit 9189b65ebf
22 changed files with 589 additions and 195 deletions

View File

@@ -0,0 +1,156 @@
import 'package:go_router/go_router.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../../features/auth/presentation/pages/login_page.dart';
import '../../features/auth/presentation/pages/register_page.dart';
import '../../features/auth/presentation/providers/auth_provider.dart';
import '../../features/auth/presentation/widgets/splash_screen.dart';
import '../../features/categories/presentation/pages/categories_page.dart';
import '../../features/categories/presentation/pages/category_detail_page.dart';
import '../../features/home/presentation/pages/home_page.dart';
import '../../features/products/presentation/pages/batch_update_page.dart';
import '../../features/products/presentation/pages/product_detail_page.dart';
import '../../features/products/presentation/pages/products_page.dart';
import '../../features/settings/presentation/pages/settings_page.dart';
import '../../shared/widgets/app_bottom_nav_shell.dart';
part 'app_router.g.dart';
/// Router configuration provider
@Riverpod(keepAlive: true)
GoRouter router(Ref ref) {
final authState = ref.watch(authProvider);
return GoRouter(
initialLocation: '/',
debugLogDiagnostics: true,
redirect: (context, state) {
final isAuthenticated = authState.isAuthenticated;
final isLoading = authState.isLoading && authState.user == null;
final isGoingToAuth = state.matchedLocation == '/login' ||
state.matchedLocation == '/register';
// Show splash screen while loading
if (isLoading) {
return '/splash';
}
// Redirect to login if not authenticated and not already going to auth pages
if (!isAuthenticated && !isGoingToAuth && state.matchedLocation != '/splash') {
return '/login';
}
// Redirect to home if authenticated and going to auth pages
if (isAuthenticated && isGoingToAuth) {
return '/';
}
return null;
},
routes: [
// Splash screen
GoRoute(
path: '/splash',
name: 'splash',
builder: (context, state) => const SplashScreen(),
),
// Auth routes
GoRoute(
path: '/login',
name: 'login',
builder: (context, state) => const LoginPage(),
),
GoRoute(
path: '/register',
name: 'register',
builder: (context, state) => const RegisterPage(),
),
// Main shell with bottom navigation
ShellRoute(
builder: (context, state, child) {
return AppBottomNavShell(child: child);
},
routes: [
// Home tab
GoRoute(
path: '/',
name: 'home',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: const HomePage(),
),
),
// Products tab
GoRoute(
path: '/products',
name: 'products',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: const ProductsPage(),
),
routes: [
// Product detail
GoRoute(
path: ':productId',
name: 'product-detail',
builder: (context, state) {
final productId = state.pathParameters['productId']!;
return ProductDetailPage(productId: productId);
},
),
// Batch update
GoRoute(
path: 'batch-update',
name: 'batch-update',
builder: (context, state) {
// Get selected products from extra parameter
final selectedProducts = state.extra as List<dynamic>?;
if (selectedProducts == null) {
// If no products provided, return to products page
return const ProductsPage();
}
return BatchUpdatePage(
selectedProducts: selectedProducts.cast(),
);
},
),
],
),
// Categories tab
GoRoute(
path: '/categories',
name: 'categories',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: const CategoriesPage(),
),
routes: [
// Category detail
GoRoute(
path: ':categoryId',
name: 'category-detail',
builder: (context, state) {
final categoryId = state.pathParameters['categoryId']!;
return CategoryDetailPage(categoryId: categoryId);
},
),
],
),
// Settings tab
GoRoute(
path: '/settings',
name: 'settings',
pageBuilder: (context, state) => NoTransitionPage(
key: state.pageKey,
child: const SettingsPage(),
),
),
],
),
],
);
}

View File

@@ -0,0 +1,55 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'app_router.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Router configuration provider
@ProviderFor(router)
const routerProvider = RouterProvider._();
/// Router configuration provider
final class RouterProvider
extends $FunctionalProvider<GoRouter, GoRouter, GoRouter>
with $Provider<GoRouter> {
/// Router configuration provider
const RouterProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'routerProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$routerHash();
@$internal
@override
$ProviderElement<GoRouter> $createElement($ProviderPointer pointer) =>
$ProviderElement(pointer);
@override
GoRouter create(Ref ref) {
return router(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(GoRouter value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<GoRouter>(value),
);
}
}
String _$routerHash() => r'3c7108371f8529a70e1e479728e8da132246bab4';