+ "{view.client.brief}" +
+{view.client.brief}
+Token: {params.token}
+Project Progress
+ ++ {view.global_progress_pct}% Complete +
++ "{view.client.brief}" +
++ Phase Progress +
++ {phase.progress_pct}% +
++ Tasks ({phase.tasks.filter(t => t.status === 'done').length} of {phase.tasks.length}) +
+ {phase.tasks.length === 0 ? ( +No tasks yet
+ ) : ( ++ {task.title} +
+ {task.description && ( ++ {task.description} +
+ )} + {/* Deliverables */} + {task.deliverables.length > 0 && ( ++ Totale Preventivo Accettato +
++ €{parseFloat(accepted_total || '0').toLocaleString('it-IT', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} +
++ {payment.label} +
++ I pagamenti sono suddivisi in due rate da 50% ciascuna. + Contattaci per domande sui dettagli. +
++ No notes yet. Decisions will appear here as they are made. +
+ ); + } + + return ( ++ {note.body} +
++ {new Date(note.created_at).toLocaleDateString('it-IT', { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + })} +
+{client.brand_name}
+Nessun cliente ancora.
++ + Crea il primo cliente + +
+| Cliente | +Totale | +Acconto | +Saldo | +Link | +
|---|
{client.brand_name}
+Nessuna fase ancora.
+ )} + {phases.map((phase) => ( ++ Le rate Acconto e Saldo vengono aggiornate automaticamente al 50% ciascuna. +
+Nessun documento ancora.
+ )} +Nessun commento ancora.
+ )} ++ {c.author === "admin" ? "iamcavalli" : "Cliente"} — {entityLabels[c.entity_id] ?? c.entity_id} +
+{c.body}
+{error}
} ++ {c.author === "admin" ? "iamcavalli" : "Tu"} +
+{c.body}
+{task?.description}
+ +{d.title}
+ {d.url && {d.url}} + {d.approved_at ? ( +✓ Approved on {d.approved_at.toLocaleDateString()}
+ ) : ( ++ {c.author === 'client' ? 'You' : 'iamcavalli'} · {c.created_at.toLocaleDateString()} +
+{c.body}
+| Colonna | +
|---|
| ... | +
+ Nessun servizio nel catalogo. Aggiungi il primo servizio qui sopra. +
+ ) : ( +| Nome | +Descrizione | +Prezzo | +Stato | ++ |
|---|
+ Nessuna voce aggiunta. Seleziona dal catalogo per iniziare. +
+ ) : ( + <> +| Voce | +Qty | +Prezzo unit. | +Subtotale | ++ |
|---|---|---|---|---|
| {item.label} | +{parseFloat(item.quantity).toLocaleString("it-IT", { minimumFractionDigits: 2 })} | ++ €{parseFloat(item.unit_price).toLocaleString("it-IT", { minimumFractionDigits: 2 })} + | ++ €{parseFloat(item.subtotal).toLocaleString("it-IT", { minimumFractionDigits: 2 })} + | ++ + | +
+ Totale calcolato: €{calculatedTotal.toLocaleString("it-IT", { minimumFractionDigits: 2 })} +
+{totalError}
} ++ Il cliente vede solo questo importo, non le singole voci del preventivo. +
+| Column | +
|---|
| Colonna | +
|---|
| … | +
Nessuna voce aggiunta. Seleziona dal catalogo per iniziare.
+ ) : ( + <> +| Voce | +Qty | +Prezzo unit. | +Subtotale | ++ |
|---|---|---|---|---|
| + {item.custom_label || item.serviceName} + | +{item.quantity} | ++ €{parseFloat(item.unit_price).toFixed(2)} + | ++ €{parseFloat(item.subtotal).toFixed(2)} + | ++ + | +
+ Totale calcolato: €{total.toFixed(2)} +
++ Il cliente vede solo questo importo, non le singole voci. +
+Nessun progetto ancora. Creane uno dal dettaglio di un cliente.
+| Progetto | +Valore | +Acconto | +Saldo | +Timer | +€/h | +
|---|
Crea un nuovo progetto per un cliente esistente.
+{client.brand_name}
+Nessun progetto ancora per questo cliente.
+ + + Crea il primo progetto + ++ {project.accepted_total && parseFloat(project.accepted_total) > 0 + ? `€${parseFloat(project.accepted_total).toLocaleString("it-IT", { minimumFractionDigits: 2 })}` + : "Preventivo non impostato"} +
+ + ))} ++ Archiviati ({archivedProjects.length}) +
+Archiviato
+ + ))} ++ {client.projectBrands.join(" | ")} +
+)} +``` + +2. Per la colonna LTV: sostituire `client.accepted_total` con `client.ltv` (che è ora la somma dei progetti). Se la colonna LTV non esiste ancora, aggiungere una colonna con `€{parseFloat(client.ltv).toLocaleString("it-IT", { minimumFractionDigits: 2 })}`. + +3. Aggiornare il tipo prop di ClientRow per includere i nuovi campi: +```typescript +// Aggiungere ai campi di ClientWithPayments usati da ClientRow: +projectBrands: string[]; +ltv: string; +``` + +Se ClientRow usa `ClientWithPayments` importato da admin-queries, il tipo sarà aggiornato automaticamente dalla modifica in A. Verificare che TypeScript non si lamenti. +