Pages corrections journal

This commit is contained in:
alma 2026-01-16 13:19:54 +01:00
parent 721e8b6030
commit 926d78a379
2 changed files with 440 additions and 7 deletions

View File

@ -5,6 +5,7 @@ import { Image, FileText, Link, List, Plus } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { useSession } from 'next-auth/react';
import { noteContentCache } from '@/lib/cache-utils';
import { HealthForm } from './health-form';
interface Note {
id: string;
@ -118,6 +119,12 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
debouncedSave();
};
// Handle content change from HealthForm (direct string update)
const handleHealthContentChange = (newContent: string) => {
setContent(newContent);
debouncedSave();
};
const debouncedSave = () => {
if (saveTimeout.current) {
clearTimeout(saveTimeout.current);
@ -264,18 +271,28 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
)}
{/* Editor Area */}
<div className="flex-1 p-4">
<div className="flex-1 overflow-y-auto">
{isLoading ? (
<div className="flex items-center justify-center h-full">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-primary"></div>
</div>
) : (
<textarea
value={content ?? ''}
onChange={handleContentChange}
placeholder="Ecrire..."
className="w-full h-full resize-none focus:outline-none bg-transparent text-carnet-text-primary placeholder-carnet-text-muted"
) : currentFolder === 'Health' ? (
// Use HealthForm for Health folder
<HealthForm
content={content}
onContentChange={handleHealthContentChange}
date={note?.lastModified}
/>
) : (
<div className="p-4">
<textarea
value={content ?? ''}
onChange={handleContentChange}
placeholder="Ecrire..."
className="w-full h-full resize-none focus:outline-none bg-transparent text-carnet-text-primary placeholder-carnet-text-muted"
style={{ minHeight: '400px' }}
/>
</div>
)}
</div>
{isSaving && (

View File

@ -0,0 +1,416 @@
"use client";
import React, { useState, useEffect } 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 {};
});
// 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)
useEffect(() => {
const timer = setTimeout(() => {
const jsonContent = JSON.stringify(data, null, 2);
onContentChange(jsonContent);
}, 100);
return () => clearTimeout(timer);
}, [data, onContentChange]);
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>
);
};