// Dati della piattaforma Stress Index. Sono ancora i dati dimostrativi del prototipo // (nessun backend HRV collegato): stanno tutti qui, così quando arriverà la sorgente vera // basterà sostituire queste costanti con le query, lasciando intatte pagine e componenti. export interface Client { id: string; name: string; initials: string; age: number; sex: 'M' | 'F'; tags: string[]; email: string; since: string; lastMeasurement: string; stress: number; alerts: number; } export const clients: Client[] = [ { id: 'c1', name: 'L. Verdi', initials: 'LV', age: 34, sex: 'F', tags: ['ansia', 'sonno'], email: 'l.verdi@esempio.it', since: '2024-02-10', lastMeasurement: '2026-07-10', stress: 62, alerts: 1 }, { id: 'c2', name: 'A. Neri', initials: 'AN', age: 45, sex: 'M', tags: ['sport', 'recupero'], email: 'a.neri@esempio.it', since: '2023-11-05', lastMeasurement: '2026-07-11', stress: 38, alerts: 0 }, { id: 'c3', name: 'G. Rossi', initials: 'GR', age: 29, sex: 'M', tags: ['lavoro', 'stress'], email: 'g.rossi@esempio.it', since: '2024-05-20', lastMeasurement: '2026-07-09', stress: 78, alerts: 2 }, { id: 'c4', name: 'S. Ferrari', initials: 'SF', age: 52, sex: 'F', tags: ['menopausa', 'sonno'], email: 's.ferrari@esempio.it', since: '2023-08-14', lastMeasurement: '2026-07-12', stress: 55, alerts: 0 }, { id: 'c5', name: 'P. Colombo', initials: 'PC', age: 40, sex: 'M', tags: ['sport', 'agonismo'], email: 'p.colombo@esempio.it', since: '2024-01-30', lastMeasurement: '2026-07-08', stress: 44, alerts: 0 }, { id: 'c6', name: 'E. Ricci', initials: 'ER', age: 61, sex: 'F', tags: ['cronico', 'riabilitazione'], email: 'e.ricci@esempio.it', since: '2022-09-01', lastMeasurement: '2026-07-11', stress: 70, alerts: 1 }, { id: 'c7', name: 'D. Marino', initials: 'DM', age: 33, sex: 'M', tags: ['lavoro', 'burnout'], email: 'd.marino@esempio.it', since: '2024-03-18', lastMeasurement: '2026-07-07', stress: 82, alerts: 2 }, { id: 'c8', name: 'C. Greco', initials: 'CG', age: 27, sex: 'F', tags: ['sport', 'studentessa'], email: 'c.greco@esempio.it', since: '2024-06-02', lastMeasurement: '2026-07-12', stress: 30, alerts: 0 }, { id: 'c9', name: 'F. Bruno', initials: 'FB', age: 48, sex: 'M', tags: ['ipertensione', 'sonno'], email: 'f.bruno@esempio.it', since: '2023-04-25', lastMeasurement: '2026-07-06', stress: 66, alerts: 1 }, { id: 'c10', name: 'V. Costa', initials: 'VC', age: 36, sex: 'F', tags: ['ansia', 'lavoro'], email: 'v.costa@esempio.it', since: '2024-07-01', lastMeasurement: '2026-07-10', stress: 58, alerts: 1 }, ]; export type Measurement = { date: string; stress: number; recovery: number; balance: number; energy: number; type: string; durationMin: number; } const clamp = (n: number) => Math.max(0, Math.min(100, Math.round(n))); const TYPES = ['Riposo', 'Lavoro', 'Sport', 'Sonno']; // Serie settimanale deterministica: l'oscillazione deriva da id + indice, così i grafici // sono sempre uguali fra server e client (nessun Math.random che sfarfalla all'idratazione). function buildSeries(clientId: string, baseStress: number, endDate: string, points: number): Measurement[] { const end = new Date(endDate); const series: Measurement[] = []; for (let i = points - 1; i >= 0; i--) { const d = new Date(end); d.setDate(d.getDate() - i * 7); const seed = clientId.charCodeAt(clientId.length - 1) + i * 13; const wobble = Math.sin(seed) * 12; const stress = clamp(baseStress + wobble); series.push({ date: d.toISOString().slice(0, 10), stress, recovery: clamp(100 - stress + Math.cos(seed) * 8), balance: clamp(70 - Math.abs(wobble) + Math.sin(seed * 2) * 6), energy: clamp(65 - (stress - 50) * 0.4 + Math.cos(seed * 1.5) * 7), type: TYPES[i % TYPES.length], durationMin: 15 + ((i * 5) % 40), }); } return series; } export const measurementsByClient: Record = { c1: buildSeries('c1', 62, '2026-07-10', 16), c2: buildSeries('c2', 38, '2026-07-11', 14), c3: buildSeries('c3', 78, '2026-07-09', 18), c4: buildSeries('c4', 55, '2026-07-12', 12), c5: buildSeries('c5', 44, '2026-07-08', 15), c6: buildSeries('c6', 70, '2026-07-11', 20), c7: buildSeries('c7', 82, '2026-07-07', 17), c8: buildSeries('c8', 30, '2026-07-12', 10), c9: buildSeries('c9', 66, '2026-07-06', 13), c10: buildSeries('c10', 58, '2026-07-10', 11), }; export interface Alert { clientId: string; clientName: string; text: string; severity: 'warn' | 'error'; when: string; } export const alerts: Alert[] = [ { clientId: 'c7', clientName: 'D. Marino', text: 'Stress elevato per 3 misurazioni consecutive', severity: 'error', when: '2026-07-07' }, { clientId: 'c3', clientName: 'G. Rossi', text: 'Recupero notturno in calo', severity: 'warn', when: '2026-07-09' }, { clientId: 'c3', clientName: 'G. Rossi', text: 'Bilancio simpatico/parasimpatico sbilanciato', severity: 'warn', when: '2026-07-05' }, { clientId: 'c1', clientName: 'L. Verdi', text: 'Qualità del sonno sotto la soglia attesa', severity: 'warn', when: '2026-07-10' }, { clientId: 'c6', clientName: 'E. Ricci', text: 'Andamento stress in peggioramento nelle ultime 4 settimane', severity: 'warn', when: '2026-07-11' }, { clientId: 'c9', clientName: 'F. Bruno', text: 'Nessuna misurazione da oltre 7 giorni', severity: 'warn', when: '2026-07-13' }, { clientId: 'c10', clientName: 'V. Costa', text: 'Picco di stress rilevato dopo sessione di lavoro prolungata', severity: 'warn', when: '2026-07-10' }, { clientId: 'c7', clientName: 'D. Marino', text: 'Energia media sotto il 30% da due settimane', severity: 'error', when: '2026-07-01' }, ]; export interface Note { clientId?: string; text: string; when: string; } export const notes: Note[] = [ { clientId: 'c1', text: 'Consigliata routine di respirazione serale, rivalutare tra 2 settimane.', when: '2026-07-10' }, { clientId: 'c3', text: 'Segnalato carico lavorativo elevato, proposto colloquio di follow-up.', when: '2026-07-09' }, { clientId: 'c7', text: 'Situazione di burnout in peggioramento, valutare invio a specialista.', when: '2026-07-07' }, { text: 'Aggiornamento protocollo misurazioni: aggiunta soglia energia minima.', when: '2026-07-05' }, { clientId: 'c6', text: 'Programma di riabilitazione in corso, buoni progressi sul recupero.', when: '2026-07-11' }, ]; export const studioKpis = { totalClients: 10, avgStress: 58, activeAlerts: 8, measurementsThisMonth: 46, retentionRate: 92, }; // `fill` colora la singola barra: le fasce basse sono "buone", le alte critiche. export const scoreDistribution = [ { range: '0-20', count: 0, fill: '#6f8f6a' }, { range: '21-40', count: 2, fill: '#6f8f6a' }, { range: '41-60', count: 3, fill: '#c08a3e' }, { range: '61-80', count: 4, fill: '#b05a4e' }, { range: '81-100', count: 1, fill: '#8d3f34' }, ]; export const segments = [ { label: 'Sportivi', count: 3, avgStress: 37 }, { label: 'Stress lavorativo', count: 4, avgStress: 69 }, { label: 'Sonno/recupero', count: 3, avgStress: 61 }, ]; export const topPerformers = [ { clientId: 'c8', name: 'C. Greco', stress: 30 }, { clientId: 'c2', name: 'A. Neri', stress: 38 }, { clientId: 'c5', name: 'P. Colombo', stress: 44 }, ]; export const criticalClients = [ { clientId: 'c7', name: 'D. Marino', stress: 82 }, { clientId: 'c3', name: 'G. Rossi', stress: 78 }, { clientId: 'c6', name: 'E. Ricci', stress: 70 }, ]; // Ultimo giorno coperto dai dati dimostrativi dello Sport. const OGGI_SPORT = '2026-07-12'; export type Session = { id: string; athleteId: string; /** Inizio della sessione, data e ora locali. */ startedAt: string; durationSec: number; /** Lo sport può non essere indicato: l'app lo ricava dal sensore solo se dichiarato. */ sport: string | null; hrAvg: number; hrMax: number; trimp: number; /** DFA Alpha1 a fine sessione; assente sulle registrazioni troppo brevi. */ dfaA1: number | null; /** Sforzo percepito 1-10, inserito a mano dall'atleta. */ rpe: number | null; }; export type Athlete = { clientId: string; name: string; sport: string | null }; export const athletes: Athlete[] = [ { clientId: 'c2', name: 'A. Neri', sport: 'Corsa' }, { clientId: 'c5', name: 'P. Colombo', sport: 'Ciclismo' }, { clientId: 'c8', name: 'C. Greco', sport: null }, ]; // Venti sessioni distribuite sugli ultimi due mesi, generate in modo deterministico dallo // stesso schema seno/coseno usato per le misurazioni: nessun valore casuale, così server e // client disegnano gli stessi grafici. function buildSessions(): Session[] { const out: Session[] = []; const fine = new Date(`${OGGI_SPORT}T00:00:00`); for (let i = 0; i < 20; i++) { const atleta = athletes[i % athletes.length]; const giorno = new Date(fine); giorno.setDate(giorno.getDate() - Math.round(i * 2.6)); const seed = i * 7 + atleta.clientId.charCodeAt(1); const ora = 7 + (i % 12); const minuti = (seed * 13) % 60; const durata = i % 9 === 0 ? 5 + (seed % 40) : 540 + Math.round(Math.abs(Math.sin(seed)) * 4400); const hrAvg = 95 + Math.round(Math.abs(Math.cos(seed)) * 55); out.push({ id: `s${i + 1}`, athleteId: atleta.clientId, startedAt: `${giorno.toISOString().slice(0, 10)}T${String(ora).padStart(2, '0')}:${String(minuti).padStart(2, '0')}`, durationSec: durata, sport: atleta.sport, hrAvg, hrMax: hrAvg + 15 + (seed % 25), trimp: durata < 300 ? 0 : Math.max(4, Math.round((durata / 60) * (hrAvg / 110))), dfaA1: durata < 300 ? null : Math.round((0.85 + Math.abs(Math.sin(seed * 1.7)) * 0.85) * 100) / 100, rpe: i % 7 === 2 ? null : 3 + (seed % 6), }); } return out.sort((a, b) => (a.startedAt < b.startedAt ? 1 : -1)); } export const sessions: Session[] = buildSessions(); // "Oggi" della piattaforma: i dati dimostrativi sono ancorati a questa data, quindi i conteggi // "giorni fa" restano coerenti invece di crescere col passare del tempo reale. export const OGGI = '2026-07-13'; export function daysSince(date: string, from: string = OGGI): number { return Math.max(0, Math.round((Date.parse(from) - Date.parse(date)) / 86_400_000)); } export function findClient(id: string): Client | null { return clients.find((c) => c.id === id) ?? null; } export const professional = { name: 'Dr. M. Bianchi', role: 'Osteopata', studio: 'Studio Bianchi — Osteopatia e Benessere', email: 'm.bianchi@esempio.it', };