feat: Client Portal redesign to Quiet Luxury + milestone stepper
- New MilestoneStepper primitive (horizontal per-phase progress) - Token-migrate portal shell, phase cards, sidebar cards, kanban to dual-theme - Soft-tint status pills (emerald/amber/muted) replacing solid badges - embedded prop on ClientDashboard fixes double-header in multi-project tabs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
import type { ClientView } from '@/lib/client-view';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
interface PaymentStatusProps {
|
||||
accepted_total: string;
|
||||
@@ -17,22 +15,22 @@ type PaymentStatusValue = 'da_saldare' | 'inviata' | 'saldato';
|
||||
|
||||
const statusConfig: Record<
|
||||
PaymentStatusValue,
|
||||
{ label: string; badgeClass: string; dotClass: string }
|
||||
{ label: string; pillClass: string }
|
||||
> = {
|
||||
da_saldare: {
|
||||
label: 'Da Saldare',
|
||||
badgeClass: 'border-transparent bg-[#2563eb] text-white',
|
||||
dotClass: 'bg-[#2563eb]',
|
||||
pillClass:
|
||||
'bg-amber-50 text-amber-700 border-amber-100 dark:bg-amber-500/10 dark:text-amber-400 dark:border-amber-500/20',
|
||||
},
|
||||
inviata: {
|
||||
label: 'Inviata',
|
||||
badgeClass: 'border-transparent bg-[#ca8a04] text-white',
|
||||
dotClass: 'bg-[#ca8a04]',
|
||||
pillClass:
|
||||
'bg-blue-50 text-blue-700 border-blue-100 dark:bg-blue-500/10 dark:text-blue-400 dark:border-blue-500/20',
|
||||
},
|
||||
saldato: {
|
||||
label: 'Saldato',
|
||||
badgeClass: 'border-transparent bg-[#16a34a] text-white',
|
||||
dotClass: 'bg-[#16a34a]',
|
||||
pillClass:
|
||||
'bg-emerald-50 text-emerald-700 border-emerald-100 dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -52,22 +50,22 @@ export function PaymentStatus({
|
||||
});
|
||||
|
||||
return (
|
||||
<Card className="rounded-lg border border-[#e5e5e5] bg-white shadow-none overflow-hidden">
|
||||
<div className="rounded-xl border border-border-light bg-card shadow-card overflow-hidden">
|
||||
{/* Totale — unico importo visibile al cliente (LOCKED) */}
|
||||
<div className="px-6 py-5 border-b border-[#e5e5e5] bg-[#f9f9f9]">
|
||||
<p className="text-xs font-semibold text-[#666666] uppercase tracking-wider mb-1">
|
||||
<div className="px-5 py-5 border-b border-border-light bg-muted">
|
||||
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-1">
|
||||
{totalLabel}
|
||||
</p>
|
||||
<p className="text-3xl font-bold text-[#1a1a1a] tracking-tight">
|
||||
<p className="text-2xl font-bold text-foreground tracking-tight">
|
||||
{totalFormatted}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Righe pagamento: solo etichetta + stato, MAI importo singolo — omesse se hideRows */}
|
||||
{!hideRows && (
|
||||
<div className="px-6 py-4 space-y-3">
|
||||
<div className="px-5 py-4 space-y-2">
|
||||
{payments.length === 0 ? (
|
||||
<p className="text-sm text-[#999999] italic py-2">
|
||||
<p className="text-sm text-muted-foreground italic py-2">
|
||||
Nessun piano di pagamento configurato.
|
||||
</p>
|
||||
) : (
|
||||
@@ -78,23 +76,18 @@ export function PaymentStatus({
|
||||
return (
|
||||
<div
|
||||
key={payment.id}
|
||||
className="flex items-center justify-between gap-4 py-2"
|
||||
className="flex items-center justify-between gap-4 rounded-lg border border-border-light p-3"
|
||||
>
|
||||
{/* Indicatore dot + etichetta */}
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span
|
||||
className={`w-2 h-2 rounded-full shrink-0 ${config.dotClass}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="text-sm font-medium text-[#1a1a1a]">
|
||||
{payment.label}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-xs font-semibold text-foreground">
|
||||
{payment.label}
|
||||
</p>
|
||||
|
||||
{/* Badge stato — nessun importo */}
|
||||
<Badge className={`text-xs shrink-0 ${config.badgeClass}`}>
|
||||
{/* Pill stato — nessun importo */}
|
||||
<span
|
||||
className={`rounded border px-2 py-1 text-[10px] font-bold uppercase shrink-0 ${config.pillClass}`}
|
||||
>
|
||||
{config.label}
|
||||
</Badge>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
@@ -103,11 +96,11 @@ export function PaymentStatus({
|
||||
)}
|
||||
|
||||
{/* Nota informativa */}
|
||||
<div className="px-6 py-3 border-t border-[#e5e5e5] bg-[#f9f9f9]">
|
||||
<p className="text-xs text-[#999999] italic">
|
||||
<div className="px-5 py-3 border-t border-border-light bg-muted">
|
||||
<p className="text-[11px] text-muted-foreground italic">
|
||||
Per dettagli o domande sui pagamenti, contattaci direttamente.
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user