longevity: #15 API della prima consulenza e flusso guidato nel check-up

Nuova API consulenza.ts (POST, autore da locals.user, redirect a
checkup?flusso=nuovo o alla scheda cliente). clienti.ts ora apre il flusso
guidato verso /consulenza?flusso=nuovo invece della scheda. checkup.ts:
un check-up NUOVO con flusso=nuovo prosegue con flusso=questionario; una
correzione lo ignora sempre.

Refs #15
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 08:21:28 +02:00
parent 498395dddb
commit 575a3988b7
3 changed files with 71 additions and 1 deletions
@@ -165,5 +165,9 @@ export const POST: APIRoute = async ({ request, locals }) => {
const params = new URLSearchParams({ salvato: String(esito.sessioneId) });
if (esito.fuoriRange.length > 0) params.set('fuori', String(esito.fuoriRange.length));
// Passo 3 → 4 del flusso guidato (#15): solo un check-up NUOVO (mai una correzione, che
// non passa da questo ramo) con flusso=nuovo prosegue verso il questionario.
const flusso = String(form.get('flusso') ?? '').trim();
if (flusso === 'nuovo') params.set('flusso', 'questionario');
return redirect(`/longevity/gestionale/cliente/${clientCode}?${params.toString()}`);
};
@@ -52,5 +52,7 @@ export const POST: APIRoute = async ({ request }) => {
telefono: telefono || undefined,
});
return redirect(`/longevity/gestionale/cliente/${code}`);
// Dopo l'apertura del fascicolo comincia il flusso guidato (#15, passo 1 → 2): prima
// consulenza, poi check-up, poi questionario — non più direttamente alla scheda.
return redirect(`/longevity/gestionale/cliente/${code}/consulenza?flusso=nuovo`);
};
@@ -0,0 +1,64 @@
import type { APIRoute } from 'astro';
import { getLongevityDb } from '../../../../lib/longevity/db';
import { salvaConsulenza } from '../../../../lib/longevity/consulenza';
export const prerender = false;
// Riservato a admin+trainer da src/lib/auth.ts (RULES, /^\/api\/longevity\/gestionale(\/|$)/).
const REGEX_CODE = /^ISL-\d{4}$/;
const redirect = (location: string): Response => new Response(null, { status: 303, headers: { Location: location } });
/**
* Salva la scheda di prima consulenza (#15). Autore SEMPRE da `locals.user`, mai dal form —
* stesso principio di giornale.ts e checkup.ts. Il flusso guidato (`flusso=nuovo`, passo 1
* → 2) prosegue verso il check-up; fuori dal flusso torna alla scheda cliente, sezione
* #consulenza dove il form e la lettura vivono.
*/
export const POST: APIRoute = async ({ request, locals }) => {
const form = await request.formData();
const clientCode = String(form.get('client_code') ?? '').trim();
const flusso = String(form.get('flusso') ?? '').trim();
if (!REGEX_CODE.test(clientCode)) {
return redirect(`/longevity/gestionale?errore=${encodeURIComponent('Codice cliente non valido.')}`);
}
// Il ritorno in caso di errore resta sulla stessa pagina del form, conservando `flusso`:
// altrimenti un errore fuori dal flusso guidato riporterebbe dentro il flusso, o viceversa.
const query = new URLSearchParams();
if (flusso !== '') query.set('flusso', flusso);
const tornaAlModulo = (testo: string) => {
const q = new URLSearchParams(query);
q.set('errore', testo);
return redirect(`/longevity/gestionale/cliente/${clientCode}/consulenza?${q.toString()}`);
};
const db = getLongevityDb();
const autore = locals.user!.username;
const esito = salvaConsulenza(db, {
clientCode,
autore,
campi: {
livello: String(form.get('livello') ?? ''),
obiettivoPrimario: String(form.get('obiettivo_primario') ?? ''),
obiettivoSpecifico: String(form.get('obiettivo_specifico') ?? ''),
dataTarget: String(form.get('data_target') ?? ''),
noteMediche: String(form.get('note_mediche') ?? ''),
storiaSportiva: String(form.get('storia_sportiva') ?? ''),
limitazioni: String(form.get('limitazioni') ?? ''),
disponibilitaGiorni: String(form.get('disponibilita_giorni') ?? ''),
fasciaOraria: String(form.get('fascia_oraria') ?? ''),
noteScreening: String(form.get('note_screening') ?? ''),
},
});
if (!esito.ok) return tornaAlModulo(esito.errore);
if (flusso === 'nuovo') {
// Passo 2 → 3 del flusso guidato (#15): dopo la consulenza si va al check-up.
return redirect(`/longevity/gestionale/cliente/${clientCode}/checkup?flusso=nuovo`);
}
return redirect(`/longevity/gestionale/cliente/${clientCode}?consulenza=salvata#consulenza`);
};