change routes with names

This commit is contained in:
2026-05-09 19:32:40 +02:00
parent 1081609530
commit 5f39d5b1ad
8 changed files with 83 additions and 26 deletions

View File

@@ -42,10 +42,26 @@ import 'package:flux/features/tickets/ui/ticket_list_screen.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
// Nota: Dovrai creare questi placeholder o file per non avere errori di compilazione const String loginRoute = 'login';
// import 'package:flux/features/master_data/master_data_hub_screen.dart'; const String setPasswordRoute = 'set-password';
// import 'package:flux/features/master_data/staff/ui/staff_screen.dart'; const String onboardingRoute = 'onboarding';
// import 'package:flux/features/master_data/store/ui/stores_screen.dart'; const String homeRoute = 'home';
const String masterDataRoute = 'master-data';
const String productsRoute = 'products';
const String companySettingsRoute = 'company-settings';
const String staffRoute = 'staff';
const String storesRoute = 'stores';
const String providersRoute = 'providers';
const String settingsRoute = 'settings';
const String themeRoute = 'theme';
const String operationsRoute = 'operations';
const String customersRoute = 'customers';
const String ticketsRoute = 'tickets';
const String ticketFormRoute = 'ticket-form';
const String operationFormRoute = 'operation-form';
const String uploadSuccessRoute = 'upload-success';
const String customerFormRoute = 'customer-form';
const String uploadRoute = 'upload';
class AppRouter { class AppRouter {
static GoRouter createRouter(SessionCubit sessionCubit) { static GoRouter createRouter(SessionCubit sessionCubit) {
@@ -97,14 +113,17 @@ class AppRouter {
// --- ROTTE DI SERVIZIO (FUORI DALLA SHELL) --- // --- ROTTE DI SERVIZIO (FUORI DALLA SHELL) ---
GoRoute( GoRoute(
path: '/login', path: '/login',
name: 'login',
builder: (context, state) => const AuthScreen(), builder: (context, state) => const AuthScreen(),
), ),
GoRoute( GoRoute(
path: '/set-password', path: '/set-password',
name: 'set-password',
builder: (context, state) => const SetPasswordScreen(), builder: (context, state) => const SetPasswordScreen(),
), ),
GoRoute( GoRoute(
path: '/onboarding', path: '/onboarding',
name: 'onboarding',
builder: (context, state) => BlocProvider( builder: (context, state) => BlocProvider(
create: (context) => OnboardingCubit( create: (context) => OnboardingCubit(
GetIt.I.get<SessionCubit>(), GetIt.I.get<SessionCubit>(),
@@ -119,15 +138,21 @@ class AppRouter {
builder: (context, state, child) => AppShell(child: child), builder: (context, state, child) => AppShell(child: child),
routes: [ routes: [
// 1. DASHBOARD // 1. DASHBOARD
GoRoute(path: '/', builder: (context, state) => const HomeScreen()), GoRoute(
path: '/',
name: homeRoute,
builder: (context, state) => const HomeScreen(),
),
// 2. HUB ANAGRAFICHE E SOTTO-ROTTE // 2. HUB ANAGRAFICHE E SOTTO-ROTTE
GoRoute( GoRoute(
path: '/master-data', path: '/master-data',
name: masterDataRoute,
builder: (context, state) => const MasterDataHubScreen(), builder: (context, state) => const MasterDataHubScreen(),
routes: [ routes: [
GoRoute( GoRoute(
path: 'products', // Diventa /master-data/products path: 'products', // Diventa /master-data/products
name: 'products',
builder: (context, state) { builder: (context, state) {
context.read<ProductsCubit>().refreshCubit(); context.read<ProductsCubit>().refreshCubit();
@@ -136,21 +161,25 @@ class AppRouter {
), ),
GoRoute( GoRoute(
path: 'company-settings', path: 'company-settings',
name: companySettingsRoute,
builder: (context, state) => BlocProvider( builder: (context, state) => BlocProvider(
create: (context) => CompanySettingsCubit(), create: (context) => CompanySettingsCubit(),
child: const CompanySettingsScreen(), child: const CompanySettingsScreen(),
), ),
), ),
GoRoute( GoRoute(
path: 'staff', // Diventa /master-data/staff path: 'staff',
name: staffRoute, // Diventa /master-data/staff
builder: (context, state) => const StaffScreen(), builder: (context, state) => const StaffScreen(),
), ),
GoRoute( GoRoute(
path: 'stores', // Diventa /master-data/stores path: storesRoute,
name: 'stores', // Diventa /master-data/stores
builder: (context, state) => const StoresScreen(), builder: (context, state) => const StoresScreen(),
), ),
GoRoute( GoRoute(
path: 'providers', // Diventa /master-data/providers path: 'providers',
name: providersRoute, // Diventa /master-data/providers
builder: (context, state) => builder: (context, state) =>
const ProvidersMasterDataScreen(), const ProvidersMasterDataScreen(),
), ),
@@ -160,16 +189,19 @@ class AppRouter {
// 3. IMPOSTAZIONI // 3. IMPOSTAZIONI
GoRoute( GoRoute(
path: '/settings', path: '/settings',
name: settingsRoute,
builder: (context, state) => const SettingsView(), builder: (context, state) => const SettingsView(),
routes: [ routes: [
GoRoute( GoRoute(
path: 'theme', path: 'theme',
name: themeRoute,
builder: (context, state) => const ThemeSettingsView(), builder: (context, state) => const ThemeSettingsView(),
), ),
], ],
), ),
GoRoute( GoRoute(
path: '/operations', path: '/operations',
name: operationsRoute,
builder: (context, state) => BlocProvider( builder: (context, state) => BlocProvider(
create: (context) => OperationListCubit(), create: (context) => OperationListCubit(),
child: const OperationListScreen(), child: const OperationListScreen(),
@@ -177,11 +209,13 @@ class AppRouter {
), ),
GoRoute( GoRoute(
path: '/customers', path: '/customers',
name: customersRoute,
builder: (context, state) => builder: (context, state) =>
const CustomersContent(), // O come si chiama il tuo widget della lista! const CustomersContent(), // O come si chiama il tuo widget della lista!
), ),
GoRoute( GoRoute(
path: '/tickets', path: '/tickets',
name: ticketsRoute,
builder: (context, state) => BlocProvider( builder: (context, state) => BlocProvider(
create: (context) => TicketListCubit(), create: (context) => TicketListCubit(),
child: const TicketListScreen(), child: const TicketListScreen(),
@@ -194,6 +228,7 @@ class AppRouter {
GoRoute( GoRoute(
// Il path sarà es. /tickets/form/123 oppure /tickets/form/new // Il path sarà es. /tickets/form/123 oppure /tickets/form/new
path: '/tickets/form/:id', path: '/tickets/form/:id',
name: ticketFormRoute,
builder: (context, state) { builder: (context, state) {
// 1. Leggiamo l'ID dall'URL // 1. Leggiamo l'ID dall'URL
final String pathId = state.pathParameters['id'] ?? 'new'; final String pathId = state.pathParameters['id'] ?? 'new';
@@ -230,10 +265,12 @@ class AppRouter {
), ),
GoRoute( GoRoute(
path: '/upload-success', path: '/upload-success',
name: uploadSuccessRoute,
builder: (context, state) => const UploadSuccessScreen(), builder: (context, state) => const UploadSuccessScreen(),
), ),
GoRoute( GoRoute(
path: '/customer/:id', path: '/customer/form/:id',
name: 'customer-form',
builder: (context, state) { builder: (context, state) {
final customer = state.extra as CustomerModel; final customer = state.extra as CustomerModel;
return BlocProvider( return BlocProvider(
@@ -248,6 +285,7 @@ class AppRouter {
GoRoute( GoRoute(
path: '/operations/form/:id', path: '/operations/form/:id',
name: operationFormRoute,
builder: (context, state) { builder: (context, state) {
final String pathId = state.pathParameters['id'] ?? 'new'; final String pathId = state.pathParameters['id'] ?? 'new';
final OperationModel? operationFromExtra = final OperationModel? operationFromExtra =
@@ -286,6 +324,7 @@ class AppRouter {
GoRoute( GoRoute(
path: '/upload/:type/:id', path: '/upload/:type/:id',
name: uploadRoute,
builder: (context, state) { builder: (context, state) {
final typeString = state.pathParameters['type']!; final typeString = state.pathParameters['type']!;
final id = state.pathParameters['id']!; final id = state.pathParameters['id']!;

View File

@@ -21,11 +21,10 @@ class QrUploadDialog extends StatelessWidget {
return BlocListener<AttachmentsBloc, AttachmentsState>( return BlocListener<AttachmentsBloc, AttachmentsState>(
listener: (context, state) { listener: (context, state) {
if (state.status == AttachmentsStatus.success) { Navigator.of(context).pop();
Navigator.of(context).pop();
}
}, },
listenWhen: (previous, current) => previous.status != current.status, listenWhen: (previous, current) =>
previous.allFiles.length < current.allFiles.length,
child: AlertDialog( child: AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
backgroundColor: theme.colorScheme.surface, backgroundColor: theme.colorScheme.surface,

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/theme/theme.dart';
import 'package:flux/features/customers/blocs/customers_cubit.dart'; import 'package:flux/features/customers/blocs/customers_cubit.dart';
import 'package:flux/features/customers/models/customer_model.dart'; import 'package:flux/features/customers/models/customer_model.dart';
@@ -109,8 +110,9 @@ class _CustomersContentState extends State<CustomersContent> {
final customer = state.customers[index]; final customer = state.customers[index];
return _CustomerTile( return _CustomerTile(
customer: customer, customer: customer,
onTap: () => context.push( onTap: () => context.pushNamed(
'/customer/${customer.id}', customerFormRoute,
pathParameters: {'id': customer.id!},
extra: customer, extra: customer,
), ),
); );

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/theme/theme.dart';
import 'package:flux/core/utils/extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/home/latest_store_operations/bloc/latest_store_operations_bloc.dart'; import 'package:flux/features/home/latest_store_operations/bloc/latest_store_operations_bloc.dart';
@@ -48,7 +49,7 @@ class _LatestOperationsCardContent extends StatelessWidget {
side: BorderSide(color: theme.dividerColor.withValues(alpha: 0.5)), side: BorderSide(color: theme.dividerColor.withValues(alpha: 0.5)),
), ),
child: InkWell( child: InkWell(
onTap: () => context.push('/operations'), onTap: () => context.pushNamed(operationsRoute),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
@@ -134,8 +135,9 @@ class _LatestOperationsCardContent extends StatelessWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final operation = state.operations[index]; final operation = state.operations[index];
return InkWell( return InkWell(
onTap: () => context.push( onTap: () => context.pushNamed(
'/operations/form/id=${operation.id}', operationFormRoute,
pathParameters: {'id': operation.id!},
extra: operation, extra: operation,
), ),
child: Padding( child: Padding(

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/theme/theme.dart';
import 'package:flux/core/utils/extensions.dart'; import 'package:flux/core/utils/extensions.dart';
import 'package:flux/features/home/latest_store_operations/ui/latest_store_operations_card.dart'; import 'package:flux/features/home/latest_store_operations/ui/latest_store_operations_card.dart';
@@ -83,7 +84,7 @@ class HomeScreen extends StatelessWidget {
color: Colors.purple, color: Colors.purple,
context: context, context: context,
onTap: () => onTap: () =>
context.push('/tickets'), // <-- Aggiunto! context.pushNamed(ticketsRoute), // <-- Aggiunto!
), ),
]), ]),
), ),
@@ -186,7 +187,10 @@ class HomeScreen extends StatelessWidget {
color: Colors.blue, color: Colors.blue,
onTap: () { onTap: () {
// Entriamo nel form! Nessun parametro extra = Nuovo Servizio // Entriamo nel form! Nessun parametro extra = Nuovo Servizio
context.push('/operations/form/new'); context.pushNamed(
operationFormRoute,
pathParameters: {'id': 'New'},
);
}, },
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
@@ -196,7 +200,7 @@ class HomeScreen extends StatelessWidget {
color: Colors.redAccent, color: Colors.redAccent,
onTap: () { onTap: () {
// Andiamo alla lista! (Da lì poi aggiungeremo il tasto "+" per il form) // Andiamo alla lista! (Da lì poi aggiungeremo il tasto "+" per il form)
context.push('/tickets/form/new'); context.pushNamed(ticketFormRoute, pathParameters: {'id': 'New'});
}, },
), ),
const SizedBox(width: 12), const SizedBox(width: 12),

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
// Mantieni i tuoi import per il tema se usi le estensioni (es. context.accent) // Mantieni i tuoi import per il tema se usi le estensioni (es. context.accent)
// import 'package:flux/core/theme/theme.dart'; // import 'package:flux/core/theme/theme.dart';
@@ -65,7 +66,7 @@ class MasterDataHubScreen extends StatelessWidget {
color: Colors.orange, color: Colors.orange,
// Usiamo .push() perché avevamo detto che i clienti // Usiamo .push() perché avevamo detto che i clienti
// stanno FUORI dalla Shell (niente BottomBar) // stanno FUORI dalla Shell (niente BottomBar)
onTap: () => context.push('/customers'), onTap: () => context.pushNamed(customersRoute),
), ),
_buildHubCard( _buildHubCard(
context, context,

View File

@@ -2,6 +2,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:flux/core/theme/theme.dart'; import 'package:flux/core/theme/theme.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@@ -28,7 +29,7 @@ class SettingsView extends StatelessWidget {
icon: Icons.business, icon: Icons.business,
subtitle: 'Configura i dati aziendali', subtitle: 'Configura i dati aziendali',
context: context, context: context,
onTap: () => context.push('/master-data/company-settings'), onTap: () => context.pushNamed(companySettingsRoute),
), ),
]), ]),
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -38,7 +39,7 @@ class SettingsView extends StatelessWidget {
title: 'Tema (FLUX Dark)', title: 'Tema (FLUX Dark)',
subtitle: 'Configurazione visiva', subtitle: 'Configurazione visiva',
context: context, context: context,
onTap: () => context.push('/settings/theme'), onTap: () => context.pushNamed(themeRoute),
), ),
]), ]),
const SizedBox(height: 24), const SizedBox(height: 24),

View File

@@ -1,9 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/routes/app_router.dart';
import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart'; import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart';
import 'package:flux/features/tickets/blocs/ticket_list_state.dart'; import 'package:flux/features/tickets/blocs/ticket_list_state.dart';
import 'package:flux/features/tickets/models/ticket_model.dart'; import 'package:flux/features/tickets/models/ticket_model.dart';
import 'package:flux/features/tickets/models/ticket_status_extension.dart'; import 'package:flux/features/tickets/models/ticket_status_extension.dart';
import 'package:go_router/go_router.dart';
class TicketListScreen extends StatefulWidget { class TicketListScreen extends StatefulWidget {
const TicketListScreen({super.key}); const TicketListScreen({super.key});
@@ -147,7 +149,7 @@ class _TicketListScreenState extends State<TicketListScreen> {
), ),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () { onPressed: () {
// TODO: Navigare alla creazione di un nuovo ticket context.pushNamed(ticketFormRoute, pathParameters: {'id': 'New'});
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
label: const Text('Nuovo Ticket'), label: const Text('Nuovo Ticket'),
@@ -279,7 +281,14 @@ class _TicketCard extends StatelessWidget {
], ],
), ),
onTap: () { onTap: () {
// TODO: Aprire il dettaglio del ticket! context.pushNamed(
'ticket-form',
pathParameters: {'id': ticket.id!},
extra:
ticket, // <-- LA MAGIA È QUI: Passa l'oggetto intero!
// Teniamo anche il parametro URL per coerenza di routing
);
}, },
), ),
), ),