diff --git a/apps/platforms/src/pages/longevity/gestionale/cliente/[code].astro b/apps/platforms/src/pages/longevity/gestionale/cliente/[code].astro index 73bf6cf..ac71f9e 100644 --- a/apps/platforms/src/pages/longevity/gestionale/cliente/[code].astro +++ b/apps/platforms/src/pages/longevity/gestionale/cliente/[code].astro @@ -36,6 +36,7 @@ const formattaData = (iso: string) => const params = Astro.url.searchParams; const salvato = params.get('salvato'); +const corretto = params.get('corretto'); // #12: redirect di correggiCheckup dopo una correzione const fuoriCount = params.get('fuori'); const errore = params.get('errore'); const verificata = params.get('verificata'); @@ -69,6 +70,7 @@ const messaggioVerifica = {errore &&

{errore}

} {salvato &&

Check-up salvato (sessione #{salvato}).

} + {corretto &&

Check-up corretto (sessione #{corretto}): punteggi ricalcolati.

} {messaggioVerifica &&

{messaggioVerifica}

} {fuoriCount && (

@@ -131,7 +133,9 @@ const messaggioVerifica = {sessioni.map((s) => ( - {formattaData(s.data)} + + {formattaData(s.data)} + {ETICHETTA_TIPO[s.tipo]} {s.operatore ?? '—'} {s.numeroMisure} diff --git a/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/checkup.astro b/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/checkup.astro index 35a41a4..e5bef49 100644 --- a/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/checkup.astro +++ b/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/checkup.astro @@ -2,10 +2,14 @@ // Il modulo del check-up manuale: i campi letti dal registro (campiDelCheckup), // raggruppati per asse come il modulo cartaceo. L'invio va all'API del gestionale, che fa // la validazione vera (pages/api/longevity/gestionale/checkup.ts) — qui c'è solo il form. +// +// Con ?sessione= (#12) lo stesso form diventa una correzione: data e campi +// precompilati dalla sessione, hidden sessione_id in più, campi attivi alla data DELLA +// SESSIONE (non a oggi) — un test dismesso da allora resterebbe comunque compilabile. import Longevity from '../../../../../layouts/Longevity.astro'; import { getLongevityDb } from '../../../../../lib/longevity/db'; import { clienteDaCodice } from '../../../../../lib/longevity/anagrafica'; -import { campiDelCheckup } from '../../../../../lib/longevity/gestionale'; +import { campiDelCheckup, misureDellaSessione } from '../../../../../lib/longevity/gestionale'; export const prerender = false; @@ -13,28 +17,42 @@ const { code } = Astro.params; const cliente = code ? clienteDaCodice(code) : null; if (!cliente) return new Response('Cliente non trovato', { status: 404 }); +const db = getLongevityDb(); const oggi = new Date().toISOString().slice(0, 10); -const gruppi = campiDelCheckup(getLongevityDb(), oggi); + +const sessioneParam = Astro.url.searchParams.get('sessione'); +const sessioneId = sessioneParam !== null ? Number(sessioneParam) : null; +const sessione = sessioneId !== null && Number.isInteger(sessioneId) ? misureDellaSessione(db, sessioneId) : null; +// Una sessione di un altro cliente o non di tipo checkup non è un modulo modificabile da +// questa scheda: stesso trattamento di un codice cliente inesistente. +if (sessioneId !== null && (!sessione || sessione.client_code !== cliente.client_code || sessione.tipo !== 'checkup')) { + return new Response('Sessione non trovata', { status: 404 }); +} + +const dataForm = sessione?.data ?? oggi; +const gruppi = campiDelCheckup(db, dataForm); +const valori = new Map(sessione?.misure.map((m) => [m.test_id, m.valore_num]) ?? []); const errore = Astro.url.searchParams.get('errore'); ---

-

Nuovo check-up

-

{cliente.cognome} {cliente.nome} — {cliente.client_code}. Lascia vuoto ciò che non hai misurato oggi.

+

{sessione ? 'Modifica check-up' : 'Nuovo check-up'}

+

{cliente.cognome} {cliente.nome} — {cliente.client_code}. Lascia vuoto ciò che non hai misurato.

{errore &&

{errore}

}
+ {sessione && } {gruppi.map((g) => ( @@ -43,7 +61,7 @@ const errore = Astro.url.searchParams.get('errore'); {g.campi.map((c) => ( ))} @@ -51,7 +69,7 @@ const errore = Astro.url.searchParams.get('errore');
Annulla - +
diff --git a/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/sessione/[id].astro b/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/sessione/[id].astro new file mode 100644 index 0000000..e279adb --- /dev/null +++ b/apps/platforms/src/pages/longevity/gestionale/cliente/[code]/sessione/[id].astro @@ -0,0 +1,96 @@ +--- +// Il dettaglio di una sessione (#12): data, tipo, operatore, misure con valore/unità e +// stato di fuori-range/verifica. Da qui si apre la correzione di un check-up +// (checkup.astro?sessione=) — un questionario resta di sola lettura, la sua correzione +// non è questa issue. Un id che non esiste, o di un altro cliente, è un 404: non c'è niente +// da mostrare per una sessione che non è la sua. +import Longevity from '../../../../../../layouts/Longevity.astro'; +import { getLongevityDb } from '../../../../../../lib/longevity/db'; +import { clienteDaCodice } from '../../../../../../lib/longevity/anagrafica'; +import { misureDellaSessione, campiDelCheckup, type MisuraDiSessione } from '../../../../../../lib/longevity/gestionale'; +import { formattaNumero } from '../../../../../../lib/longevity/formato'; + +export const prerender = false; + +const { code, id } = Astro.params; +const cliente = code ? clienteDaCodice(code) : null; +if (!cliente) return new Response('Cliente non trovato', { status: 404 }); + +const sessioneId = id ? Number(id) : NaN; +const db = getLongevityDb(); +const sessione = Number.isInteger(sessioneId) ? misureDellaSessione(db, sessioneId) : null; +if (!sessione || sessione.client_code !== cliente.client_code) { + return new Response('Sessione non trovata', { status: 404 }); +} + +const ETICHETTA_TIPO: Record<'checkup' | 'questionario', string> = { + checkup: 'Check-up', questionario: 'Questionario', +}; +const ETICHETTA_VERIFICA: Record<'confermata' | 'scartata', string> = { + confermata: 'Confermata', scartata: 'Scartata', +}; +const formattaData = (iso: string) => + new Date(`${iso}T00:00:00`).toLocaleDateString('it-IT', { day: '2-digit', month: 'short', year: 'numeric' }); + +// Un check-up si raggruppa per asse come il modulo che lo ha compilato (campiDelCheckup); +// un questionario non ha un raggruppamento del genere nel codice — resta un'unica sezione, +// già ordinata per asse da misureDellaSessione. +type Sezione = { asse: string | null; misure: MisuraDiSessione[] }; +let sezioni: Sezione[]; +if (sessione.tipo === 'checkup') { + const perTestId = new Map(sessione.misure.map((m) => [m.test_id, m])); + sezioni = campiDelCheckup(db, sessione.data) + .map((g) => ({ + asse: g.asse, + misure: g.campi.map((c) => perTestId.get(c.id)).filter((m): m is MisuraDiSessione => m !== undefined), + })) + .filter((s) => s.misure.length > 0); +} else { + sezioni = [{ asse: null, misure: sessione.misure }]; +} +--- + +
+
+

{ETICHETTA_TIPO[sessione.tipo]} del {formattaData(sessione.data)}

+

{cliente.cognome} {cliente.nome} — {cliente.client_code} · operatore {sessione.operatore ?? '—'}

+
+
+ {sessione.tipo === 'checkup' && ( + Modifica + )} + Torna alla scheda +
+
+ + {sezioni.map((s) => ( +
+ {s.asse &&

{s.asse}

} + + + + {s.misure.map((m) => ( + + + + + + ))} + +
TestValoreStato
{m.etichetta} + {m.valore_num !== null ? formattaNumero(m.valore_num) : (m.valore_txt ?? '—')} + {m.unita ? ` ${m.unita}` : ''} + + {m.fuori_range === 0 + ? '—' + : m.verifica + ? ETICHETTA_VERIFICA[m.verifica] + : 'Da verificare'} +
+
+ ))} +