longevity: #15 pagine del flusso guidato: consulenza, check-up, scheda cliente

Nuova pagina consulenza.astro (radio per livello e obiettivo, niente
select). checkup.astro mostra "Passo 3 di 4" e porta avanti flusso=nuovo,
con «Salta» verso la scheda. La scheda cliente ([code].astro) mostra la
sezione "Prima consulenza" (letta, Modifica/Compila) e, con
flusso=questionario, il riquadro "Passo 4 di 4" che rimanda a "Crea
accesso" se il cliente non lo ha ancora.

Refs #15
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 08:21:33 +02:00
parent 575a3988b7
commit 8aeb25f930
3 changed files with 169 additions and 1 deletions
@@ -13,6 +13,7 @@ import { misureDaVerificare } from '../../../../lib/longevity/misure';
import { refertoDi, ultimaSessioneDi } from '../../../../lib/longevity/vista';
import { formattaNumero } from '../../../../lib/longevity/formato';
import { vociDelGiornale } from '../../../../lib/longevity/giornale';
import { consulenzaDi, OBIETTIVI } from '../../../../lib/longevity/consulenza';
export const prerender = false;
@@ -28,6 +29,8 @@ const daVerificare = misureDaVerificare(db, cliente.client_code);
const ultimaId = ultimaSessioneDi(db, cliente.client_code);
const referto = ultimaId !== null ? refertoDi(db, ultimaId) : null;
const voci = vociDelGiornale(db, cliente.client_code); // #16: giornale di bordo, solo staff
const consulenza = consulenzaDi(db, cliente.client_code); // #15: prima consulenza, solo staff
const ETICHETTA_OBIETTIVO = new Map(OBIETTIVI.map((o) => [o.chiave, o.etichetta]));
const ETICHETTA_TIPO: Record<'checkup' | 'questionario', string> = {
checkup: 'Check-up',
@@ -55,6 +58,10 @@ const MESSAGGIO_GIORNALE: Record<'aggiunta' | 'cancellata', string> = {
};
const messaggioGiornale =
giornaleEsito === 'aggiunta' || giornaleEsito === 'cancellata' ? MESSAGGIO_GIORNALE[giornaleEsito] : null;
const consulenzaEsito = params.get('consulenza'); // #15: 'salvata', dal redirect dell'API consulenza
// Passo 4 del flusso guidato per un cliente nuovo (#15): dopo il check-up si torna qui con
// ?flusso=questionario — il questionario resta del cliente, quindi qui c'è solo l'indicazione.
const flusso = params.get('flusso');
---
<Longevity
title={`${cliente.cognome} ${cliente.nome}`}
@@ -82,6 +89,20 @@ const messaggioGiornale =
{corretto && <p class="lg-card">Check-up corretto (sessione #{corretto}): punteggi ricalcolati.</p>}
{messaggioVerifica && <p class="lg-card">{messaggioVerifica}</p>}
{messaggioGiornale && <p class="lg-card">{messaggioGiornale}</p>}
{consulenzaEsito === 'salvata' && <p class="lg-card">Prima consulenza salvata.</p>}
{flusso === 'questionario' && (
<div class="lg-card">
<p class="lg-score__label">Passo 4 di 4 — Questionario</p>
{cliente.ha_accesso ? (
<p>Il questionario lo compila il cliente dal suo accesso, anche sul tablet del centro.</p>
) : (
<>
<p>Il questionario lo compila il cliente dal suo accesso, anche sul tablet del centro: crealo per continuare.</p>
<a class="lg-btn" href={`/longevity/gestionale/cliente/${cliente.client_code}/accesso`}>Crea accesso al referto</a>
</>
)}
</div>
)}
{fuoriCount && (
<p class="lg-misura--fuori-range">
{fuoriCount} {Number(fuoriCount) === 1 ? 'misura è' : 'misure sono'} fuori dal range di
@@ -96,6 +117,31 @@ const messaggioGiornale =
<p>Data di nascita: {cliente.data_nascita ? formattaData(cliente.data_nascita) : '—'}</p>
</div>
<div class="lg-card" id="consulenza">
<div class="lg-head--azioni">
<p class="lg-score__label">Prima consulenza</p>
<a class="lg-btn" href={`/longevity/gestionale/cliente/${cliente.client_code}/consulenza`}>
{consulenza ? 'Modifica' : 'Compila'}
</a>
</div>
{!consulenza ? (
<p class="lg-muted">Non ancora compilata.</p>
) : (
<>
<p>Livello: {consulenza.livello ?? '—'}</p>
<p>Obiettivo primario: {consulenza.obiettivo_primario ? ETICHETTA_OBIETTIVO.get(consulenza.obiettivo_primario) ?? consulenza.obiettivo_primario : '—'}</p>
<p>Obiettivo specifico: {consulenza.obiettivo_specifico ?? '—'}</p>
<p>Data target: {consulenza.data_target ? formattaData(consulenza.data_target) : '—'}</p>
<p>Note mediche: {consulenza.note_mediche ?? '—'}</p>
<p>Storia sportiva: {consulenza.storia_sportiva ?? '—'}</p>
<p>Limitazioni fisiche attuali: {consulenza.limitazioni ?? '—'}</p>
<p>Disponibilità: {consulenza.disponibilita_giorni ?? '—'} giorni/settimana</p>
<p>Fascia oraria preferita: {consulenza.fascia_oraria ?? '—'}</p>
<p>Note screening: {consulenza.note_screening ?? '—'}</p>
</>
)}
</div>
<div class="lg-card" id="giornale">
<p class="lg-score__label">Giornale di bordo</p>
<p class="lg-muted">Solo lo staff lo vede. Una nota sbagliata si cancella e si riscrive: non si modifica.</p>