'use client'; /** * Étape 2: Personnalisation avancée avec tableau interactif * Interface de configuration détaillée des phases et budgets */ import React, { useState, useRef, useEffect } from 'react'; import { Card } from 'primereact/card'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { InputNumber } from 'primereact/inputnumber'; import { InputText } from 'primereact/inputtext'; import { Checkbox } from 'primereact/checkbox'; import { Calendar } from 'primereact/calendar'; import { TabView, TabPanel } from 'primereact/tabview'; import { Accordion, AccordionTab } from 'primereact/accordion'; import { Tag } from 'primereact/tag'; import { Badge } from 'primereact/badge'; import { Toast } from 'primereact/toast'; import { Message } from 'primereact/message'; import { Divider } from 'primereact/divider'; import { Slider } from 'primereact/slider'; import { ToggleButton } from 'primereact/togglebutton'; import { PhaseTemplate, SousPhaseTemplate, WizardConfiguration } from '../PhaseGenerationWizard'; interface CustomizationStepProps { configuration: WizardConfiguration; onConfigurationChange: (config: WizardConfiguration) => void; } const CustomizationStep: React.FC = ({ configuration, onConfigurationChange }) => { const toast = useRef(null); const [activeTabIndex, setActiveTabIndex] = useState(0); const [expandedPhases, setExpandedPhases] = useState>({}); const [editingCell, setEditingCell] = useState(null); // État local pour les modifications const [localPhases, setLocalPhases] = useState( configuration.phasesSelectionnees || [] ); // Synchroniser avec la configuration parent seulement si les localPhases sont vides useEffect(() => { if (configuration.phasesSelectionnees && localPhases.length === 0) { console.log('🔄 Synchronisation initiale localPhases avec configuration:', configuration.phasesSelectionnees.length, 'phases'); setLocalPhases([...configuration.phasesSelectionnees]); } }, [configuration.phasesSelectionnees, localPhases.length]); // Log les changements de localPhases pour debug useEffect(() => { console.log('📋 LocalPhases mis à jour:', localPhases.length, 'phases, budget total:', localPhases.reduce((sum, p) => sum + (p.budgetEstime || 0), 0)); }, [localPhases]); // Mettre à jour la configuration const updateConfiguration = (updates: Partial) => { onConfigurationChange({ ...configuration, ...updates }); }; // Mettre à jour une phase const updatePhase = (phaseId: string, updates: Partial) => { setLocalPhases(prevPhases => { const updatedPhases = prevPhases.map(phase => phase.id === phaseId ? { ...phase, ...updates } : phase ); // Recalculer le budget et la durée globale const budgetTotal = updatedPhases.reduce((sum, p) => sum + (p.budgetEstime || 0), 0); const dureeTotal = updatedPhases.reduce((sum, p) => sum + (p.dureeEstimee || 0), 0); console.log('💰 Budget mis à jour:', { phaseId, updates, budgetTotal, dureeTotal }); // Mettre à jour la configuration avec les nouvelles données setTimeout(() => { updateConfiguration({ phasesSelectionnees: updatedPhases, budgetGlobal: budgetTotal, dureeGlobale: dureeTotal }); }, 0); return updatedPhases; }); }; // Mettre à jour une sous-phase const updateSousPhase = (phaseId: string, sousPhaseId: string, updates: Partial) => { setLocalPhases(prevPhases => { const updatedPhases = prevPhases.map(phase => { if (phase.id === phaseId) { const updatedSousPhases = phase.sousPhases.map(sp => sp.id === sousPhaseId ? { ...sp, ...updates } : sp ); return { ...phase, sousPhases: updatedSousPhases }; } return phase; }); setTimeout(() => { updateConfiguration({ phasesSelectionnees: updatedPhases }); }, 0); return updatedPhases; }); }; // Templates pour le tableau des phases const checkboxTemplate = (rowData: PhaseTemplate) => ( p.id === rowData.id)} onChange={(e) => { setLocalPhases(prevPhases => { const newPhases = e.checked ? [...prevPhases, rowData] : prevPhases.filter(p => p.id !== rowData.id); setTimeout(() => { updateConfiguration({ phasesSelectionnees: newPhases }); }, 0); return newPhases; }); }} /> ); const nomTemplate = (rowData: PhaseTemplate) => (
{rowData.nom}
{rowData.description}
); const categorieTemplate = (rowData: PhaseTemplate) => ( ); const dureeTemplate = (rowData: PhaseTemplate) => { const isEditing = editingCell === `duree_${rowData.id}`; return isEditing ? ( updatePhase(rowData.id, { dureeEstimee: e.value || 0 })} onBlur={() => setEditingCell(null)} suffix=" j" min={1} max={365} autoFocus className="w-full" /> ) : (
setEditingCell(`duree_${rowData.id}`)} > {rowData.dureeEstimee} jours
); }; const budgetTemplate = (rowData: PhaseTemplate) => { const isEditing = editingCell === `budget_${rowData.id}`; return isEditing ? ( { const newValue = e.value || 0; console.log('💰 Modification budget phase:', rowData.id, 'ancien:', rowData.budgetEstime, 'nouveau:', newValue); updatePhase(rowData.id, { budgetEstime: newValue }); }} onBlur={() => { console.log('💰 Fin édition budget phase:', rowData.id); setEditingCell(null); }} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === 'Tab') { setEditingCell(null); } }} mode="decimal" minFractionDigits={0} maxFractionDigits={2} min={0} placeholder="0" autoFocus className="w-full" style={{ textAlign: 'right' }} /> ) : (
{ console.log('💰 Début édition budget phase:', rowData.id); setEditingCell(`budget_${rowData.id}`); }} title="Cliquer pour modifier le budget" > {new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', minimumFractionDigits: 0 }).format(rowData.budgetEstime)}
); }; const competencesTemplate = (rowData: PhaseTemplate) => (
{rowData.competencesRequises.slice(0, 3).map((comp, index) => ( ))} {rowData.competencesRequises.length > 3 && ( )}
); const sousPhaseTemplate = (rowData: PhaseTemplate) => (