'use client'; import React, { useState, useEffect, useRef } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { InputText } from 'primereact/inputtext'; import { InputTextarea } from 'primereact/inputtextarea'; import { InputNumber } from 'primereact/inputnumber'; import { Calendar } from 'primereact/calendar'; import { Dropdown } from 'primereact/dropdown'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Toast } from 'primereact/toast'; import { ProgressSpinner } from 'primereact/progressspinner'; import { Toolbar } from 'primereact/toolbar'; import { Dialog } from 'primereact/dialog'; import { devisService, clientService } from '../../../../../services/api'; import { formatCurrency } from '../../../../../utils/formatters'; import type { Devis, LigneDevis } from '../../../../../types/btp'; const EditDevisPage = () => { const params = useParams(); const router = useRouter(); const toast = useRef(null); const [devis, setDevis] = useState({ id: '', numero: '', dateEmission: new Date(), dateValidite: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), objet: '', description: '', montantHT: 0, montantTTC: 0, tauxTVA: 20, statut: 'BROUILLON', actif: true, lignes: [] }); const [clients, setClients] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [showLigneDialog, setShowLigneDialog] = useState(false); const [editingLigne, setEditingLigne] = useState(null); const [nouvelleLigne, setNouvelleLigne] = useState({ designation: '', quantite: 1, unite: 'unité', prixUnitaire: 0, montantHT: 0 }); const devisId = params.id as string; const statutOptions = [ { label: 'Brouillon', value: 'BROUILLON' }, { label: 'En attente', value: 'EN_ATTENTE' }, { label: 'Accepté', value: 'ACCEPTE' }, { label: 'Refusé', value: 'REFUSE' }, { label: 'Expiré', value: 'EXPIRE' } ]; const uniteOptions = [ { label: 'Unité', value: 'unité' }, { label: 'Heure', value: 'heure' }, { label: 'Jour', value: 'jour' }, { label: 'M²', value: 'm²' }, { label: 'M³', value: 'm³' }, { label: 'ML', value: 'ml' }, { label: 'Kg', value: 'kg' }, { label: 'Tonne', value: 'tonne' }, { label: 'Forfait', value: 'forfait' } ]; useEffect(() => { loadData(); }, [devisId]); const loadData = async () => { try { setLoading(true); const [devisResponse, clientsResponse] = await Promise.all([ devisService.getById(devisId), clientService.getAll() ]); setDevis(devisResponse.data); setClients(clientsResponse.data); } catch (error) { console.error('Erreur lors du chargement:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les données' }); } finally { setLoading(false); } }; const calculateMontants = () => { const montantHT = (devis.lignes || []).reduce((sum, ligne) => sum + (ligne.montantHT || 0), 0); const montantTTC = montantHT * (1 + devis.tauxTVA / 100); setDevis(prev => ({ ...prev, montantHT, montantTTC })); }; useEffect(() => { calculateMontants(); }, [devis.lignes, devis.tauxTVA]); const handleSave = async () => { try { setSaving(true); await devisService.update(devisId, devis); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Devis modifié avec succès' }); router.push(`/devis/${devisId}`); } catch (error) { console.error('Erreur lors de la sauvegarde:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Erreur lors de la sauvegarde' }); } finally { setSaving(false); } }; const handleAddLigne = () => { setEditingLigne(null); setNouvelleLigne({ designation: '', quantite: 1, unite: 'unité', prixUnitaire: 0, montantHT: 0 }); setShowLigneDialog(true); }; const handleEditLigne = (ligne: LigneDevis, index: number) => { setEditingLigne({ ...ligne, index }); setNouvelleLigne({ ...ligne }); setShowLigneDialog(true); }; const handleSaveLigne = () => { const montantHT = nouvelleLigne.quantite * nouvelleLigne.prixUnitaire; const ligneComplete = { ...nouvelleLigne, montantHT }; const nouvelleLignes = [...(devis.lignes || [])]; if (editingLigne && editingLigne.index !== undefined) { nouvelleLignes[editingLigne.index] = ligneComplete; } else { nouvelleLignes.push(ligneComplete); } setDevis(prev => ({ ...prev, lignes: nouvelleLignes })); setShowLigneDialog(false); }; const handleDeleteLigne = (index: number) => { const nouvelleLignes = [...(devis.lignes || [])]; nouvelleLignes.splice(index, 1); setDevis(prev => ({ ...prev, lignes: nouvelleLignes })); }; const toolbarStartTemplate = () => (
); const toolbarEndTemplate = () => (
); const actionBodyTemplate = (rowData: LigneDevis, options: any) => (
); if (loading) { return (
); } return (
{/* Informations générales */}
setDevis(prev => ({ ...prev, numero: e.target.value }))} className="w-full" required />
setDevis(prev => ({ ...prev, objet: e.target.value }))} className="w-full" required />
setDevis(prev => ({ ...prev, clientId: e.value }))} optionLabel="nom" optionValue="id" placeholder="Sélectionner un client" className="w-full" filter />
setDevis(prev => ({ ...prev, dateEmission: e.value || new Date() }))} className="w-full" dateFormat="dd/mm/yy" />
setDevis(prev => ({ ...prev, dateValidite: e.value || new Date() }))} className="w-full" dateFormat="dd/mm/yy" />
setDevis(prev => ({ ...prev, statut: e.value }))} className="w-full" />
setDevis(prev => ({ ...prev, description: e.target.value }))} className="w-full" rows={4} />
setDevis(prev => ({ ...prev, tauxTVA: e.value || 0 }))} className="w-full" suffix="%" min={0} max={100} />
{/* Lignes du devis */}
rowData.quantite?.toLocaleString('fr-FR')} /> formatCurrency(rowData.prixUnitaire)} /> formatCurrency(rowData.montantHT)} />
{/* Dialog pour ajouter/modifier une ligne */} setShowLigneDialog(false)} style={{ width: '600px' }} footer={
} >
setNouvelleLigne(prev => ({ ...prev, designation: e.target.value }))} className="w-full" required />
setNouvelleLigne(prev => ({ ...prev, quantite: e.value || 0 }))} className="w-full" min={0} required />
setNouvelleLigne(prev => ({ ...prev, unite: e.value }))} className="w-full" />
setNouvelleLigne(prev => ({ ...prev, prixUnitaire: e.value || 0 }))} className="w-full" mode="currency" currency="EUR" locale="fr-FR" min={0} required />
{formatCurrency(nouvelleLigne.quantite * nouvelleLigne.prixUnitaire)}
); }; export default EditDevisPage;