diff --git a/design-reference/DESIGN-SYSTEM.md b/design-reference/DESIGN-SYSTEM.md index af4633c..00a0d8e 100644 --- a/design-reference/DESIGN-SYSTEM.md +++ b/design-reference/DESIGN-SYSTEM.md @@ -146,3 +146,23 @@ across all future admin pages. | `LeadTable` | `src/components/admin/leads/LeadTable.tsx` | Luxury table restyle: `bg-card rounded-xl shadow-card`, uppercase muted headers, `hover:bg-muted/40` rows, uses `StatusBadge`. | | `LeadsKanbanBoard` | `src/components/admin/leads/LeadsKanbanBoard.tsx` | Kanban restyle: `bg-muted/60` columns with count pills, `bg-card` cards with `hover:border-primary/30`. Uses `@dnd-kit`, keeps all 6 lead stages. | | `LeadsViewToggle` | `src/components/admin/leads/LeadsViewToggle.tsx` | Wires `SearchInput` + `SegmentedToggle` together with the table/kanban views. | +| `MilestoneStepper` | `src/components/client/MilestoneStepper.tsx` | Client-portal horizontal milestone stepper: one node per real phase, connecting line filled by `global_progress_pct`. Done = filled `bg-primary` ✓, active = `border-primary` outline, upcoming = `bg-muted`. | + +### Client Portal restyle notes + +The `/client/[token]` portal was migrated to the same "Quiet Luxury" tokens +(applied 2026-07-10). Key conventions specific to the client-facing surface: + +- **Header**: `bg-card` sticky bar, three zones — `iamcavalli | Client Portal` + (left), brand name centered, "Area Riservata Protetta" emerald pill (right). +- **Status pills** (phases, payments) use soft tints, not solid fills: + emerald-50/700 (done/saldato), amber-50/700 (in corso/da saldare), + `bg-muted`/`text-muted-foreground` (upcoming) — each with a `dark:` variant. +- **Phase cards** (`PhaseCard`): `rounded-xl border-border-light bg-card + shadow-card`, progress bar colored per status (emerald/amber/`bg-border`). +- Sidebar cards (`OffersSection`, `PaymentStatus`, `DocumentsSection`, + `NotesSection`, `TranscriptsSection`) all follow `rounded-xl border-border-light + bg-card shadow-card`. +- `ClientDashboard` takes an `embedded` prop: when rendered inside the + multi-project tabs wrapper (`page.tsx`), it drops its own header/footer/canvas + so the page-level chrome isn't duplicated. diff --git a/src/app/client/[token]/page.tsx b/src/app/client/[token]/page.tsx index ed22f63..d6d10a2 100644 --- a/src/app/client/[token]/page.tsx +++ b/src/app/client/[token]/page.tsx @@ -106,10 +106,10 @@ export default async function ClientPage({ if (projects.length === 0) { return ( -
+
-

{client.name}

-

Nessun progetto disponibile al momento.

+

{client.name}

+

Nessun progetto disponibile al momento.

); @@ -132,22 +132,23 @@ export default async function ClientPage({ const projectViews = await Promise.all(projects.map((p) => getProjectView(p.id))); return ( -
-
-
-
- - iamcavalli - -

- {client.brand_name} -

-
-
+
+
+
+ iamcavalli + | + Client Portal +
+
+

{client.brand_name}

+
+
+ + Area Riservata Protetta
-
+
{projects.map((p) => ( @@ -166,9 +167,10 @@ export default async function ClientPage({ view={projectViewToClientView(client, view)} token={client.token} comments={view.comments as unknown as Comment[]} + embedded /> ) : ( -

Progetto non disponibile.

+

Progetto non disponibile.

)} ); @@ -176,12 +178,8 @@ export default async function ClientPage({
-
-
-

- Questa è la tua dashboard privata — non condividere il link. -

-
+
+ Questa è la tua dashboard privata — non condividere il link.
); diff --git a/src/components/client-dashboard.tsx b/src/components/client-dashboard.tsx index c7703f2..248f7cd 100644 --- a/src/components/client-dashboard.tsx +++ b/src/components/client-dashboard.tsx @@ -1,6 +1,5 @@ import type { ClientView } from '@/lib/client-view'; import type { Comment } from '@/db/schema'; -import { Progress } from '@/components/ui/progress'; import { RefreshCw } from 'lucide-react'; import { PhaseTimeline } from './phase-timeline'; import { PaymentStatus } from './payment-status'; @@ -9,6 +8,7 @@ import { NotesSection } from './notes-section'; import { TranscriptsSection } from './transcripts-section'; import { PhaseViewToggle } from './client/kanban/PhaseViewToggle'; import { OffersSection } from './client/OffersSection'; +import { MilestoneStepper } from './client/MilestoneStepper'; import { ChatProvider } from './client/ChatProvider'; import { ChatPanel } from './client/ChatPanel'; @@ -16,9 +16,12 @@ interface ClientDashboardProps { view: ClientView; token: string; comments: Comment[]; + /** When rendered inside the multi-project tabs wrapper, the page already + * provides the portal header + footer — skip them here to avoid duplicates. */ + embedded?: boolean; } -export function ClientDashboard({ view, token, comments }: ClientDashboardProps) { +export function ClientDashboard({ view, token, comments, embedded = false }: ClientDashboardProps) { // Determine payment display mode based on active offers const retainerOffer = view.activeOffers?.find((o) => o.offer_type === "retainer"); const hasRetainer = !!retainerOffer; @@ -30,37 +33,38 @@ export function ClientDashboard({ view, token, comments }: ClientDashboardProps) return ( -
- {/* Header */} -
-
-
- +
+ {/* Header portale — iamcavalli · Client Portal | brand | area protetta */} + {!embedded && ( +
+
+ iamcavalli -

+ | + Client Portal +

+ +
+

{view.client.brand_name}

-
-
-
- {/* Barra progresso globale — nascosta per retainer (fasi non tracciate) */} - {!hasRetainer && ( -
-
-
-

Avanzamento Progetto

-

{view.global_progress_pct}%

-
- +
+ + Area Riservata Protetta
-
+
+ )} + + {/* Milestone stepper — nascosto per retainer (fasi non tracciate) */} + {!hasRetainer && ( + )} {/* Layout principale */} -
+
{/* ── Sidebar sinistra ── */} @@ -70,14 +74,14 @@ export function ClientDashboard({ view, token, comments }: ClientDashboardProps) {/* 1° Offerte Attive */} {view.activeOffers && view.activeOffers.length > 0 && (
-

Offerte Attive

+

Offerte Attive

)} {/* 2° Pagamenti */}
-

Pagamenti

+

Pagamenti

-

Documenti & File

+

Documenti & File

{view.notes.length > 0 && (
-

Note & Decisioni

+

Note & Decisioni

)} {view.transcripts.length > 0 && (
-

Transcript Chiamate

+

Transcript Chiamate

)} @@ -113,16 +117,16 @@ export function ClientDashboard({ view, token, comments }: ClientDashboardProps)
{hasRetainer ? (
-

+

Fasi del Progetto

-
- - +
+ +
-

Servizio in abbonamento ricorrente

-

+

Servizio in abbonamento ricorrente

+

Non ci sono fasi di progetto da tracciare. Le fasi compaiono qui quando viene avviata un'offerta a progetto.

@@ -141,12 +145,8 @@ export function ClientDashboard({ view, token, comments }: ClientDashboardProps)
-