Chore — Router cleanup, orfano rimosso, vendor dashboard collegato
Commit:
chore(router): register vendor dashboard, remove orphan create_campaign screen· Branch:edit/mobile-audit-ux-polish· Audit: 2026-04-20 UX polish (finding C4)
Cosa non andava
L’audit ha identificato tre tipi di “codice sospetto” nel layer UI:
- Duplicato di flusso accessibile:
CreateCampaignScreenera uno screen pienamente implementato, ma il flusso “creare campagne” è già coperto daCreateEventScreen(registrato su/home/create-event, raggiungibile dalCreationBottomSheet). Zero route nel router, zero riferimenti reali, genuine orphan. - Screen polished non registrato:
VendorDashboardScreen— una B2B dashboard per venue/organizer (biglietti venduti, entrate, views profilo, feedback) completa di UI, tokens brand allineati, ma senza route nel router. Un asset compiuto che giaceva inutilizzato. - Falsi orfani da non toccare (corretti in fase di verifica):
CrewMatchmakingWizard→ raggiungibile viashowModalBottomSheetdafriends_screen.dart:122echats_screen.dart:246.CreateSquadScreen→ il nome file dice_screen.dartma la classe esportata èCreateSquadSheet(bottom sheet). È invocato dal feed comeonCreateTapcallback delSquadBentoSection. Questa asimmetria file↔class è ciò che ha fatto credere all’audit iniziale che fosse orfano.
Decisioni
| Orfano candidato | Reale status | Decisione |
|---|---|---|
CreateCampaignScreen | Duplicato venue + zero reference | Rimosso (+ cartella features/campaigns/ rimossa, era single-file) |
VendorDashboardScreen | Polished, self-referenced | Registrato a /profile/vendor-dashboard |
CreateSquadScreen (file → CreateSquadSheet class) | Bottom sheet USATA dal feed | Invariato (lint: rinominare file → create_squad_sheet.dart in pass futuro) |
CrewMatchmakingWizard | Usato via showModalBottomSheet | Invariato (deep-link non adatto — rompe drag gesture) |
Diff riassuntivo
lib/core/router/app_router.dart
import 'package:flow_app/features/social/screens/create_crew_screen.dart';
import 'package:flow_app/features/reviews/screens/create_review_screen.dart';
import 'package:flow_app/features/gamification/screens/leaderboard_screen.dart';
+import 'package:flow_app/features/dashboard/screens/vendor_dashboard_screen.dart'; GoRoute(
path: 'leaderboard',
parentNavigatorKey: rootNavigatorKey,
builder: (context, state) => const LeaderboardScreen(),
),
+ GoRoute(
+ path: 'vendor-dashboard',
+ parentNavigatorKey: rootNavigatorKey,
+ builder: (context, state) => const VendorDashboardScreen(),
+ ),
],Rimozione
lib/features/campaigns/screens/create_campaign_screen.dart(deleted)lib/features/campaigns/(cartella vuota rimossa)
Perché il vendor dashboard sotto /profile e non un branch a sé
La navigation shell ha 4 branch (home / search / social / profile). Creare un 5° branch “Organizer” lo trasformerebbe in un’icona permanente nella bottom nav, ma solo una frazione degli utenti ha un profilo venue o PR. Un branch per una minoranza = UI debt per la maggioranza.
Soluzione minima: il ramo /profile ospita già pr-dashboard (PR panel), leaderboard, my-crews, verification-request, ticket-wallet. Vendor dashboard è un concept parallelo → stessa casa semantica. In un pass futuro il ProfileScreen avrà una sezione “Business tools” condizionale (visibile solo a utenti con role == venue || role == pr).
Decisioni deferite
- UI entry-point nel ProfileScreen: al momento
/profile/vendor-dashboardè raggiungibile solo via deep-link (context.push('/profile/vendor-dashboard')). Aggiungere un tile discoverable richiede prima (a) conferma che il datouser.roleè in schema Supabase (b) una skeleton UI per i dati reali (i dati attuali sono mock hardcoded). Da fare in un task dedicato “venue profile surface”. - Import inutilizzato di
go_routerinvendor_dashboard_screen.dart: lasciato — non in scope di questo chore. Sarà preso dal prossimo pass di lint cleanup. Rename: fatto in commitcreate_squad_screen.dart→create_squad_sheet.dart666575c(round 2 polish). Import infeed_screen.dartaggiornato.- Wizard matchmaking come deep-link: non aggiungere
/social/matchmaking. Una wizard full-route avrebbe semantica diversa (history stack + back gesture) che non corrisponde all’esperienza pensata (sheet che si può chiudere con drag).
Verifica
flutter analyze lib/core/router/app_router.dart \
lib/features/feed/screens/feed_screen.dart \
lib/features/dashboard/screens/vendor_dashboard_screen.dart \
lib/features/social/screens/create_squad_screen.dart
# → No issues found!Check manuale:
-
context.push('/profile/vendor-dashboard')da qualsiasi entry-point raggiunge la dashboard - Il feed ancora si carica, mostra le bento squad, e tap su “Crea squad” apre la bottom sheet
- Nessun errore “undefined name ‘CreateCampaignScreen’” in
flutter analyze
Lessons
- “Orfano” va verificato, non dedotto. L’audit iniziale aveva marcato 3 candidati orfani. La verifica ha confermato solo uno. Gli altri due erano falsi positivi per motivi diversi:
CrewMatchmakingWizard→ invocato viashowModalBottomSheet(non viaGoRoute). Grep solo suGoRoutel’avrebbe mancato.CreateSquadScreen→ nome file diverso dal nome classe. Grep suCreateSquadScreennon trova nulla; grep suCreateSquadSheettrova 3 call site. La lezione operativa: grep sul nome del simbolo, non del file.
- Nome file ↔ nome classe: mantenere coerenza. Un file
create_squad_screen.dartche esportaCreateSquadSheetè un’ambiguità che costa tempo di indagine ogni volta che qualcuno ci inciampa. Convenzione flow:*_screen.dart→ class*Screen;*_sheet.dart→ class*Sheet. Deviazioni = debt. - Una route registrata è una promessa. Registrare
VendorDashboardScreensignifica che da qui in avanti il layer UI garantisce l’esistenza di una destinazione/profile/vendor-dashboard. Code che dipende da questa route (future deep-link notifications, share urls) ora può farsi avanti senza paura di URL 404. È il meccanismo con cui i routers “contrattualizzano” l’app. - Delete-then-restore è OK se il safety net esiste. Questo chore ha avuto una falsa partenza: ho rimosso
create_squad_screen.dartprima di verificare che la classe al suo interno fosseCreateSquadSheet. La restore è stata immediata perché esisteva una copia nei.worktrees/*/lib/...— backups parallel branch. La lezione: un ambiente con worktree multipli sopravvive agli errori di chi prova cose. Un solo working tree + zero remote = un’unica copia di verità = zero margine di errore.