NeahStable/components/carnet/health-form.tsx
2026-01-16 13:35:30 +01:00

425 lines
19 KiB
TypeScript

"use client";
import React, { useState, useEffect, useRef } from 'react';
import { Calendar, Activity, Heart, Pill, Droplet, Dumbbell, FileText } from 'lucide-react';
interface HealthData {
// 1. Informations de base
date?: string;
poids?: number;
temperature?: number;
tension?: string; // Format: "120/80"
frequenceCardiaque?: number;
// 2. État de santé / symptômes
maladie?: string;
symptomes?: string;
niveauDouleur?: number; // 0-10
niveauEnergie?: 'faible' | 'moyen' | 'bon';
qualiteSommeil?: 'mauvais' | 'moyen' | 'bon' | number; // ou 1-5
// 3. Médicaments et soins
medicaments?: string;
traitementEnCours?: boolean;
consultationMedicale?: boolean;
notesMedicales?: string;
// 4. Habitudes & mode de vie
hydratation?: number; // verres d'eau
activitePhysique?: 'aucune' | 'légère' | 'intense';
dureeActivite?: number; // minutes
alimentationParticuliere?: boolean;
commentaireAlimentation?: string;
stress?: 'faible' | 'moyen' | 'élevé';
// 5. Champ libre
notesPersonnelles?: string;
}
interface HealthFormProps {
content: string;
onContentChange: (content: string) => void;
date?: string;
}
export const HealthForm: React.FC<HealthFormProps> = ({ content, onContentChange, date }) => {
const [data, setData] = useState<HealthData>(() => {
// Parse existing content if available
if (content) {
try {
return JSON.parse(content);
} catch {
// If not JSON, try to parse as markdown or return empty
return {};
}
}
return {};
});
// Use ref to track last sent content to prevent infinite loops
const lastSentContentRef = useRef<string>('');
// Initialize date if not set
useEffect(() => {
if (!data.date && date) {
setData(prev => ({ ...prev, date: date.split('T')[0] }));
} else if (!data.date) {
setData(prev => ({ ...prev, date: new Date().toISOString().split('T')[0] }));
}
}, [data.date, date]);
// Update parent content whenever data changes (with a small delay to avoid too many updates)
// Only update if content actually changed to prevent infinite loops
useEffect(() => {
const jsonContent = JSON.stringify(data, null, 2);
// Only update if content is different from last sent content
if (jsonContent !== lastSentContentRef.current) {
const timer = setTimeout(() => {
lastSentContentRef.current = jsonContent;
onContentChange(jsonContent);
}, 500); // Increased delay to reduce updates
return () => clearTimeout(timer);
}
}, [data, onContentChange]); // Stable dependencies
const updateField = (field: keyof HealthData, value: any) => {
setData(prev => ({ ...prev, [field]: value }));
};
return (
<div className="flex flex-col h-full bg-carnet-bg overflow-y-auto">
<div className="p-6 space-y-6">
{/* 1. Informations de base */}
<section className="border-b border-carnet-border pb-4">
<div className="flex items-center space-x-2 mb-4">
<Calendar className="h-5 w-5 text-carnet-text-primary" />
<h3 className="text-lg font-semibold text-carnet-text-primary">Informations de base</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Date
</label>
<input
type="date"
value={data.date || ''}
onChange={(e) => updateField('date', e.target.value)}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Poids (kg)
</label>
<input
type="number"
step="0.1"
value={data.poids || ''}
onChange={(e) => updateField('poids', e.target.value ? parseFloat(e.target.value) : undefined)}
placeholder="Ex: 70.5"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Température corporelle (°C)
</label>
<input
type="number"
step="0.1"
value={data.temperature || ''}
onChange={(e) => updateField('temperature', e.target.value ? parseFloat(e.target.value) : undefined)}
placeholder="Ex: 37.2"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Tension artérielle (optionnel)
</label>
<input
type="text"
value={data.tension || ''}
onChange={(e) => updateField('tension', e.target.value)}
placeholder="Ex: 120/80"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Fréquence cardiaque (bpm)
</label>
<input
type="number"
value={data.frequenceCardiaque || ''}
onChange={(e) => updateField('frequenceCardiaque', e.target.value ? parseInt(e.target.value) : undefined)}
placeholder="Ex: 72"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
</div>
</section>
{/* 2. État de santé / symptômes */}
<section className="border-b border-carnet-border pb-4">
<div className="flex items-center space-x-2 mb-4">
<Activity className="h-5 w-5 text-carnet-text-primary" />
<h3 className="text-lg font-semibold text-carnet-text-primary">État de santé / symptômes</h3>
</div>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Maladie / état
</label>
<input
type="text"
value={data.maladie || ''}
onChange={(e) => updateField('maladie', e.target.value)}
placeholder="Ex: grippe, rhume, migraine, fatigue, aucun"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Symptômes
</label>
<textarea
value={data.symptomes || ''}
onChange={(e) => updateField('symptomes', e.target.value)}
placeholder="Ex: fièvre, toux, maux de tête, douleurs, nausées..."
rows={3}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Niveau de douleur (0-10)
</label>
<input
type="number"
min="0"
max="10"
value={data.niveauDouleur || ''}
onChange={(e) => updateField('niveauDouleur', e.target.value ? parseInt(e.target.value) : undefined)}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Niveau d'énergie
</label>
<select
value={data.niveauEnergie || ''}
onChange={(e) => updateField('niveauEnergie', e.target.value as 'faible' | 'moyen' | 'bon' || undefined)}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="">Sélectionner</option>
<option value="faible">Faible</option>
<option value="moyen">Moyen</option>
<option value="bon">Bon</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Qualité du sommeil
</label>
<select
value={data.qualiteSommeil || ''}
onChange={(e) => {
const value = e.target.value;
if (value === 'mauvais' || value === 'moyen' || value === 'bon') {
updateField('qualiteSommeil', value);
} else if (value) {
updateField('qualiteSommeil', parseInt(value));
} else {
updateField('qualiteSommeil', undefined);
}
}}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="">Sélectionner</option>
<option value="mauvais">Mauvais</option>
<option value="moyen">Moyen</option>
<option value="bon">Bon</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>
</div>
</div>
</section>
{/* 3. Médicaments et soins */}
<section className="border-b border-carnet-border pb-4">
<div className="flex items-center space-x-2 mb-4">
<Pill className="h-5 w-5 text-carnet-text-primary" />
<h3 className="text-lg font-semibold text-carnet-text-primary">Médicaments et soins</h3>
</div>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Médicaments pris
</label>
<textarea
value={data.medicaments || ''}
onChange={(e) => updateField('medicaments', e.target.value)}
placeholder="Ex: Paracétamol 500mg, 2 comprimés"
rows={2}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-center space-x-2">
<input
type="checkbox"
id="traitementEnCours"
checked={data.traitementEnCours || false}
onChange={(e) => updateField('traitementEnCours', e.target.checked)}
className="w-4 h-4 text-primary border-carnet-border rounded focus:ring-primary"
/>
<label htmlFor="traitementEnCours" className="text-sm text-carnet-text-primary">
Traitement en cours
</label>
</div>
<div className="flex items-center space-x-2">
<input
type="checkbox"
id="consultationMedicale"
checked={data.consultationMedicale || false}
onChange={(e) => updateField('consultationMedicale', e.target.checked)}
className="w-4 h-4 text-primary border-carnet-border rounded focus:ring-primary"
/>
<label htmlFor="consultationMedicale" className="text-sm text-carnet-text-primary">
Consultation médicale
</label>
</div>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Notes médicales
</label>
<textarea
value={data.notesMedicales || ''}
onChange={(e) => updateField('notesMedicales', e.target.value)}
placeholder="Notes médicales..."
rows={3}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
</div>
</section>
{/* 4. Habitudes & mode de vie */}
<section className="border-b border-carnet-border pb-4">
<div className="flex items-center space-x-2 mb-4">
<Dumbbell className="h-5 w-5 text-carnet-text-primary" />
<h3 className="text-lg font-semibold text-carnet-text-primary">Habitudes & mode de vie (optionnel)</h3>
</div>
<div className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Hydratation (verres d'eau / jour)
</label>
<input
type="number"
value={data.hydratation || ''}
onChange={(e) => updateField('hydratation', e.target.value ? parseInt(e.target.value) : undefined)}
placeholder="Ex: 8"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Activité physique
</label>
<select
value={data.activitePhysique || ''}
onChange={(e) => updateField('activitePhysique', e.target.value as 'aucune' | 'légère' | 'intense' || undefined)}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="">Sélectionner</option>
<option value="aucune">Aucune</option>
<option value="légère">Légère</option>
<option value="intense">Intense</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Durée de l'activité (minutes)
</label>
<input
type="number"
value={data.dureeActivite || ''}
onChange={(e) => updateField('dureeActivite', e.target.value ? parseInt(e.target.value) : undefined)}
placeholder="Ex: 30"
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
<div>
<label className="block text-sm font-medium text-carnet-text-primary mb-1">
Stress
</label>
<select
value={data.stress || ''}
onChange={(e) => updateField('stress', e.target.value as 'faible' | 'moyen' | 'élevé' || undefined)}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
>
<option value="">Sélectionner</option>
<option value="faible">Faible</option>
<option value="moyen">Moyen</option>
<option value="élevé">Élevé</option>
</select>
</div>
</div>
<div>
<div className="flex items-center space-x-2 mb-2">
<input
type="checkbox"
id="alimentationParticuliere"
checked={data.alimentationParticuliere || false}
onChange={(e) => updateField('alimentationParticuliere', e.target.checked)}
className="w-4 h-4 text-primary border-carnet-border rounded focus:ring-primary"
/>
<label htmlFor="alimentationParticuliere" className="text-sm text-carnet-text-primary">
Alimentation particulière
</label>
</div>
{data.alimentationParticuliere && (
<textarea
value={data.commentaireAlimentation || ''}
onChange={(e) => updateField('commentaireAlimentation', e.target.value)}
placeholder="Commentaire sur l'alimentation..."
rows={2}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
)}
</div>
</div>
</section>
{/* 5. Champ libre */}
<section>
<div className="flex items-center space-x-2 mb-4">
<FileText className="h-5 w-5 text-carnet-text-primary" />
<h3 className="text-lg font-semibold text-carnet-text-primary">Notes personnelles</h3>
</div>
<div>
<textarea
value={data.notesPersonnelles || ''}
onChange={(e) => updateField('notesPersonnelles', e.target.value)}
placeholder="Ex: Mal dormi, début de grippe, me sens mieux aujourd'hui..."
rows={4}
className="w-full px-3 py-2 border border-carnet-border rounded-md text-sm text-carnet-text-primary bg-white focus:outline-none focus:ring-1 focus:ring-primary"
/>
</div>
</section>
</div>
</div>
);
};