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}
}
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 ?? '—'}
+
+
+
+
+ {sezioni.map((s) => (
+
+ {s.asse &&
{s.asse}
}
+
+ | Test | Valore | Stato |
+
+ {s.misure.map((m) => (
+
+ | {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'}
+ |
+
+ ))}
+
+
+
+ ))}
+