'use client'; import React, { useState, useEffect, useRef } from 'react'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { InputText } from 'primereact/inputtext'; import { Card } from 'primereact/card'; import { Dialog } from 'primereact/dialog'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Tag } from 'primereact/tag'; import { Dropdown } from 'primereact/dropdown'; import { Calendar } from 'primereact/calendar'; import { InputTextarea } from 'primereact/inputtextarea'; import { InputNumber } from 'primereact/inputnumber'; import { devisService, clientService } from '../../../services/api'; import { formatDate, formatCurrency } from '../../../utils/formatters'; import { ErrorHandler } from '../../../services/errorHandler'; import type { Devis } from '../../../types/btp'; import { ActionButtonGroup, ViewButton, EditButton, DeleteButton, PrintButton, ActionButton } from '../../../components/ui/ActionButton'; const DevisPage = () => { const [devis, setDevis] = useState([]); const [clients, setClients] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [selectedDevis, setSelectedDevis] = useState([]); const [devisDialog, setDevisDialog] = useState(false); const [deleteDevisDialog, setDeleteDevisDialog] = useState(false); const [deleteDevisssDialog, setDeleteDevisssDialog] = useState(false); const [devisItem, setDevisItem] = 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, client: null, chantier: null }); const [submitted, setSubmitted] = useState(false); const toast = useRef(null); const dt = useRef>(null); const statuts = [ { label: 'Brouillon', value: 'BROUILLON' }, { label: 'Envoyé', value: 'ENVOYE' }, { label: 'Accepté', value: 'ACCEPTE' }, { label: 'Refusé', value: 'REFUSE' }, { label: 'Expiré', value: 'EXPIRE' } ]; useEffect(() => { // Initialiser le gestionnaire d'erreurs ErrorHandler.setToast(toast); loadDevis(); loadClients(); }, []); const loadDevis = async () => { try { setLoading(true); const data = await devisService.getAll(); setDevis(data); } catch (error) { ErrorHandler.handleApiError(error, 'chargement des devis'); } finally { setLoading(false); } }; const loadClients = async () => { try { const data = await clientService.getAll(); setClients(data.map(client => ({ label: `${client.prenom} ${client.nom}${client.entreprise ? ' - ' + client.entreprise : ''}`, value: client.id, client: client }))); } catch (error) { ErrorHandler.handleApiError(error, 'chargement des clients'); } }; const openNew = () => { setDevisItem({ 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, client: null, chantier: null }); setSubmitted(false); setDevisDialog(true); }; const hideDialog = () => { setSubmitted(false); setDevisDialog(false); }; const hideDeleteDevisDialog = () => { setDeleteDevisDialog(false); }; const hideDeleteDevisssDialog = () => { setDeleteDevisssDialog(false); }; const saveDevis = async () => { setSubmitted(true); // Validation complète côté client const validationErrors = []; if (!devisItem.objet.trim()) { validationErrors.push("L'objet du devis est obligatoire"); } if (!devisItem.client) { validationErrors.push("Le client est obligatoire"); } if (!devisItem.numero.trim()) { validationErrors.push("Le numéro de devis est obligatoire"); } if (devisItem.montantHT <= 0) { validationErrors.push("Le montant HT doit être supérieur à 0"); } if (devisItem.tauxTVA < 0 || devisItem.tauxTVA > 100) { validationErrors.push("Le taux de TVA doit être entre 0 et 100%"); } if (!devisItem.dateValidite || devisItem.dateValidite <= new Date()) { validationErrors.push("La date de validité doit être dans le futur"); } if (validationErrors.length > 0) { toast.current?.show({ severity: 'error', summary: 'Erreurs de validation', detail: validationErrors.join(', '), life: 5000 }); return; } if (devisItem.objet.trim() && devisItem.client) { try { let updatedDevis = [...devis]; const devisToSave = { ...devisItem, client: devisItem.client ? { id: devisItem.client } : null, // Envoyer seulement l'ID du client montantTTC: devisItem.montantHT * (1 + devisItem.tauxTVA / 100) }; if (devisItem.id) { // Mise à jour du devis existant const updatedDevis = await devisService.update(devisItem.id, devisToSave); setDevis(devis.map(d => d.id === devisItem.id ? updatedDevis : d)); ErrorHandler.showSuccess('Succès', 'Devis mis à jour avec succès'); } else { // Création d'un nouveau devis const newDevis = await devisService.create(devisToSave); setDevis([...devis, newDevis]); ErrorHandler.showSuccess('Succès', 'Devis créé avec succès'); } setDevisDialog(false); setDevisItem({ 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, client: null, chantier: null }); } catch (error) { ErrorHandler.handleApiError(error, 'sauvegarde du devis'); } } }; const editDevis = (devis: Devis) => { setDevisItem({ ...devis, client: devis.client?.id || null }); setDevisDialog(true); }; const confirmDeleteDevis = (devis: Devis) => { setDevisItem(devis); setDeleteDevisDialog(true); }; const deleteDevis = async () => { try { if (devisItem.id) { await devisService.delete(devisItem.id); setDevis(devis.filter(d => d.id !== devisItem.id)); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Devis supprimé avec succès', life: 3000 }); } setDeleteDevisDialog(false); } catch (error) { console.error('Erreur lors de la suppression:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de supprimer le devis', life: 3000 }); } }; const exportCSV = () => { dt.current?.exportCSV(); }; const onInputChange = (e: React.ChangeEvent, name: string) => { const val = (e.target && e.target.value) || ''; let _devis = { ...devisItem }; (_devis as any)[name] = val; setDevisItem(_devis); }; const onDateChange = (e: any, name: string) => { let _devis = { ...devisItem }; (_devis as any)[name] = e.value; setDevisItem(_devis); }; const onNumberChange = (e: any, name: string) => { let _devis = { ...devisItem }; (_devis as any)[name] = e.value; setDevisItem(_devis); // Recalcul automatique du TTC if (name === 'montantHT' || name === 'tauxTVA') { const montantHT = name === 'montantHT' ? e.value : _devis.montantHT; const tauxTVA = name === 'tauxTVA' ? e.value : _devis.tauxTVA; _devis.montantTTC = montantHT * (1 + tauxTVA / 100); setDevisItem(_devis); } }; const onDropdownChange = (e: any, name: string) => { let _devis = { ...devisItem }; (_devis as any)[name] = e.value; setDevisItem(_devis); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (