// Il radar a sette assi del referto: isola React perché recharts ha bisogno del DOM. // Due serie sovrapposte sugli stessi sette assi (recharts vuole un solo `data` condiviso, // non può disegnare un poligono che copre solo alcuni assi): // - "noto": l'area piena, coi valori congelati che la sessione ha davvero. Dove il dato // manca vale 0 — non si inventa un centro pieno per una misura che non c'è, si lascia // che l'area si ritiri, onestamente, verso il centro; // - "potenziale": il perimetro tratteggiato. Dove il dato c'è coincide col bordo di // "noto" (stesso valore, la linea tratteggiata sparisce dietro quella piena); dove // manca si allarga fino al massimo (100) — è la parte che CHIUDE il perimetro, il gesto // su cui si regge l'interfaccia: non un errore, un invito a completare quell'asse. // Sotto il grafico, l'elenco leggibile di cosa completerebbe ogni asse ancora tratteggiato, // letto da `mancano` (calcolato in vista.ts, mai qui: questo componente non tocca il db). import { ResponsiveContainer, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, } from 'recharts'; import type { AsseVista } from '../../lib/longevity/vista'; interface Props { assi: AsseVista[]; } // Stessi colori del sito (come in DataChart.tsx, che per lo stesso motivo — attributi SVG, // non proprietà CSS — non passa var(--...) a recharts): l'accento e il tratteggio di // longevity.css, non un colore nuovo. const ACCENTO = '#9c8b70'; const TRATTEGGIO = '#d8d2c8'; const LINEA = '#e4dfd7'; const TESTO_CHIARO = '#8a8a8a'; export default function RadarAssi({ assi }: Props) { const dati = assi.map((a) => ({ nome: a.nome, noto: a.valore ?? 0, potenziale: a.valore ?? 100, })); const incompleti = assi.filter((a) => a.mancano.length > 0); return (
{/* La spiegazione del linguaggio visivo viene PRIMA del grafico che spiega, non dopo: chi legge deve sapere cosa sta guardando prima di guardarlo. */}

L'area piena è quello che sappiamo davvero; il perimetro tratteggiato è il resto dell'asse, dove il dato non c'è ancora.

{/* il perimetro tratteggiato si disegna per primo: quello pieno gli va sopra */}
{incompleti.length > 0 && (
{/* L'invito concreto: l'elenco sotto è nomi di test, da solo non dice cosa fare. Questi test si fanno in palestra con lo staff, non a casa da soli. */}

Questi test si fanno in sala, con il trainer: prenota la prossima sessione per completare il quadro.

{incompleti.map((a) => (

{a.nome}

    {a.mancano.map((m) =>
  • {m}
  • )}
))}
)}
); }