Skip to main content

🧩 Composizione dell’interfaccia dopo il login

Questa pagina spiega come si compone la UI quando l’utente è autenticato e ha almeno un accesso ad una company attiva.
Il contenitore principale è DashboardComponent (src/dashboards/dashboard), che ospita la navigazione delle feature e formatta la vista tramite componenti di layout.


🔭 Contesto di routing

L’area dashboard è protetta da AuthGuard e CompanyGuard.
Dentro dashboard vengono caricati lazy i moduli delle feature (es. elabel, wines, company, dispenser, …):

{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard, CompanyGuard],
children: [
{ path: '', loadChildren: () => import('../dashboards/home-page/home-page.module').then(m => m.HomePageModule) },
{ path: 'elabel', loadChildren: () => import('../dashboards/elabel/elabel.module').then(m => m.ElabelComponentModule) },
{ path: 'wines', loadChildren: () => import('../dashboards/wine/wine.module').then(m => m.WineModule) },
{ path: 'company', loadChildren: () => import('../dashboards/company/company.module').then(m => m.CompanyModule) },
{ path: 'dispenser', loadChildren: () => import('../dashboards/dispenser/dispenser.module').then(m => m.DispenserModule) },
{ path: 'seller-panel', loadChildren: () => import('../dashboards/seller-panel/stock-listing/stock-listing.module').then(m => m.StockListingModule) },
{ path: 'cantina', loadChildren: () => import('../dashboards/cantina/cantina.module').then(m => m.CantinaModule) },
{ path: 'wine-list', loadChildren: () => import('../dashboards/wine-list/wine-list.module').then(m => m.WineListModule) },
]
}

🏗️ Struttura ad alto livello

  • DashboardComponent → root della vista autenticata con company; costruisce le tab verticali (in base al tipo di company e ruolo utente) e veicola i flussi dati principali (utente, company selezionata, elenco accessi, suggerimenti ricerca, tema, ecc.).
  • AppPageLayoutComponentlayout della pagina (sidebar con tab verticali, top bar, messaggi, area contenuto, footer) e gestione responsive/mobile (riduzione sidebar, chiusura automatica su navigazione).
  • AppTopBarComponent → top bar con user info, search bar, selettore company (pannello cambio company e collegamento a nuove company), e azioni rapide (es. Stripe portal).

Il contenuto della feature corrente è renderizzato nel router-outlet interno al layout.


🧱 DashboardComponent (root area autenticata)

Responsabilità chiave

  • Orchestrazione dei dati osservabili:
    • user$, companyAccesses$, selectedCompanyAccess$, canChangeCompany$.
    • showEnterpriseCompanyAccessPanel$ (flag UI contestuale).
    • mainBarSuggestions$ (suggerimenti ricerca).
  • Costruzione dinamica delle tab verticali (exampleTabs: TabSectionType[]) in base a:
    • selectedCompanyAccess.company.typeWINERY (Cantina) vs PROFESSIONAL.
    • selectedCompanyAccess.role.name → abilita/disabilita voci (es. wines solo per Admin/WineManager nelle Cantine).
  • Gestione tema (dark/light) applicato al root element.
  • Reazioni di navigazione:
    • Se nessuna company selezionata dopo init store → company-connect.
    • Se company in pending (role assente o status PENDING*) → company-pending-verification.
    • Aggiorna canChangeUserAcces in store valutando l’URL (calculateCanChangeUserAccessFromUrl). Se la rotta (url) contiene edit o create non permette di cambiare azienda perchè non possiamo cambiare azienda in fase di creazione o modifica (chiaramente).

Struttura del template

<app-page-layout [verticalTabs]="exampleTabs">
<router-outlet></router-outlet>
</app-page-layout>

Il layout riceve le tab verticali e ospita il contenuto della feature corrente.


🧭 AppPageLayoutComponent (layout e navigazione)

Cosa fornisce

  • Sidebar con tab verticali (albi-vertical-tabs), con:
    • Sezione principale (Home, E-label, Wines, Dispenser, …).
    • Sezione inferiore (Company, Profile).
    • Riduzione/espansione sidebar e switch tema.
  • Top bar (slot <ng-content> che viene popolato da AppTopBarComponent quando showTopbar è true).
  • Messaggi di pagina (notifiche, avvisi pending, link rapidi).
  • Area contenuto con scroll e wrapper di impaginazione.
  • Pannello amministrativo (solo per utenti gruppo Admin) per selezionare company al volo (ricerca + impostazione access).

Dati/dipendenze principali

  • selectedUserAccess$: access attivo → abilita/disabilita voci.
  • showEnterpriseCompanyAccessPanel$: mostra pannello enterprise se necessario.
  • user$: dati utente (avatar, nome).
  • Responsive: isMobileView$ e isSidebarReduced$ per UX mobile.

⬆️ AppTopBarComponent (testata e cambio company)

Funzioni principali

  • User area → avatar + nome, link rapido al profilo (profile/info).
  • Search bar → suggerimenti calcolati da MAIN_BAR_SUGGESTIONS (tradotti).
  • Azione Stripe → apre il customer portal per la company corrente.
  • Selettore company:
    • Legge companyAccesses$ (gruppate per company con eventuali location figlie).
    • Mostra pannello di cambio company se canChangeCompany$ è true.
    • changeSelectedCompany(...) → dispatch changeSelectedUserAcces, poi:
      • access ACTIVE/role presente → naviga dashboard.
      • access PENDING* → naviga company-pending-verification.
    • navigateToOnboardingConnect() → forza disaccoppiamento e naviga company-connect.

Sincronizzazione con il router

  • Su evento Scroll aggiorna canChangeUserAcces in store (stessa logica del DashboardComponent).

🧠 Flussi reattivi (dati condivisi)

  • Store (NgRx) come fonte unica:
    • AUTHENTICATION_SELECTORS → utente loggato.
    • USER_ACCES_SELECTORS → accessi utente, access selezionato, flag UI (es. selectShowEnterpriseAccessPanel, selectCanChangeUserAcces).
  • TranslateService → costruisce etichette tab localizzate.
  • BackendService → ricerche company (pannello admin nel layout), Stripe portal (top bar).

🗂️ Tab verticali (policy per tipo di company)

  • Cantina (WINERY) → tab estese: home, elabel, wines, dispenser, seller-panel (WIP), cantina, wine-list, sezione inferiore company, profile.
    Ruoli abilitanti (esempi dal codice):
    • wines, elabelAdmin / WineManager.
    • dispenserAdmin / CantinaManager.
  • Professional → set ridotto: niente tab creazione/gestione wines (non produce vino).
    Presenza di dispenser, seller-panel (WIP), cantina, wine-list, company, profile con policy di ruolo coerenti.

🧵 Sequenza di interazione (semplificata)

sequenceDiagram
autonumber
participant Router
participant Dashboard as DashboardComponent
participant Layout as AppPageLayoutComponent
participant Topbar as AppTopBarComponent
participant Store as NgRx Store

Router->>Dashboard: entra in /dashboard (AuthGuard + CompanyGuard OK)
Dashboard->>Store: subscribe selectedCompanyAccess, user, flags
Dashboard->>Dashboard: build verticalTabs (company.type, role)
Dashboard->>Layout: [verticalTabs] + render <router-outlet>
Layout->>Topbar: proietta top bar (ng-content) se showTopbar
Topbar->>Store: subscribe selectedCompanyAccess, companyAccesses, canChangeCompany
Topbar-->>Router: cambio company -> dispatch changeSelectedUserAcces
Store-->>Dashboard: selectedCompanyAccess aggiornata
Dashboard-->>Router: se PENDING -> /company-pending-verification
Router-->>Layout: carica feature module nel router-outlet

✅ Cosa deve ricordare chi subentra

  • DashboardComponent governa tabs e routing interno in base a tipo company e ruolo.
  • AppPageLayoutComponent gestisce layout, sidebar, topbar, notifiche, responsive.
  • AppTopBarComponent è il punto unico per cambiare company, ricerche e shortcut utente.
  • Tutto è reattivo: leggere sempre dallo Store e non bypassare le guardie (AuthGuard, CompanyGuard).
  • Aggiunta di nuove feature → nuovo lazy module figlio di dashboard, nuova tab coerente con policy (ruolo/tipo company), eventuali label in translations.