'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 { Tag } from 'primereact/tag'; import { Divider } from 'primereact/divider'; import { Toast } from 'primereact/toast'; import { ProgressSpinner } from 'primereact/progressspinner'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Timeline } from 'primereact/timeline'; import { Badge } from 'primereact/badge'; import { Toolbar } from 'primereact/toolbar'; import { Menu } from 'primereact/menu'; import { ProgressBar } from 'primereact/progressbar'; import { factureService } from '../../../../services/api'; import { formatDate, formatCurrency } from '../../../../utils/formatters'; import type { Facture } from '../../../../types/btp'; import { StatutFacture } from '../../../../types/btp'; const FactureDetailPage = () => { const params = useParams(); const router = useRouter(); const toast = useRef(null); const menuRef = useRef(null); const [facture, setFacture] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const factureId = params.id as string; useEffect(() => { loadFacture(); }, [factureId]); const loadFacture = async () => { try { setLoading(true); const response = await factureService.getById(factureId); setFacture(response); } catch (error) { console.error('Erreur lors du chargement de la facture:', error); setError('Impossible de charger la facture'); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger la facture' }); } finally { setLoading(false); } }; const getStatutSeverity = (statut: string) => { switch (statut) { case 'PAYEE': return 'success'; case 'EN_RETARD': return 'danger'; case 'PARTIELLEMENT_PAYEE': return 'warning'; case 'ENVOYEE': return 'info'; case 'BROUILLON': return 'secondary'; default: return 'info'; } }; const getTypeSeverity = (type: string) => { switch (type) { case 'FACTURE': return 'primary'; case 'ACOMPTE': return 'info'; case 'SITUATION': return 'warning'; case 'SOLDE': return 'success'; default: return 'secondary'; } }; const menuItems = [ { label: 'Modifier', icon: 'pi pi-pencil', command: () => router.push(`/factures/${factureId}/edit`) }, { label: 'Dupliquer', icon: 'pi pi-copy', command: () => router.push(`/factures/${factureId}/duplicate`) }, { separator: true }, { label: 'Marquer comme payée', icon: 'pi pi-check', command: () => handleMarkAsPaid(), disabled: facture?.statut === 'PAYEE' }, { label: 'Enregistrer paiement partiel', icon: 'pi pi-money-bill', command: () => handlePartialPayment() }, { separator: true }, { label: 'Imprimer', icon: 'pi pi-print', command: () => window.print() }, { label: 'Télécharger PDF', icon: 'pi pi-download', command: () => handleDownloadPDF() }, { label: 'Envoyer par email', icon: 'pi pi-send', command: () => handleSendEmail() }, { separator: true }, { label: 'Supprimer', icon: 'pi pi-trash', className: 'text-red-500', command: () => handleDelete() } ]; const handleMarkAsPaid = async () => { try { await factureService.update(factureId, { statut: StatutFacture.PAYEE }); loadFacture(); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Facture marquée comme payée' }); } catch (error) { toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Erreur lors de la mise à jour' }); } }; const handlePartialPayment = () => { // TODO: Ouvrir dialog pour paiement partiel toast.current?.show({ severity: 'info', summary: 'Info', detail: 'Fonctionnalité de paiement partiel en cours de développement' }); }; const handleDownloadPDF = async () => { try { // TODO: Implémenter le téléchargement PDF toast.current?.show({ severity: 'info', summary: 'Info', detail: 'Téléchargement PDF en cours de développement' }); } catch (error) { toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Erreur lors du téléchargement' }); } }; const handleSendEmail = () => { // TODO: Ouvrir dialog d'envoi email toast.current?.show({ severity: 'info', summary: 'Info', detail: 'Envoi par email en cours de développement' }); }; const handleDelete = async () => { try { await factureService.delete(factureId); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Facture supprimée avec succès' }); router.push('/factures'); } catch (error) { toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Erreur lors de la suppression' }); } }; const calculateProgress = () => { if (!facture) return 0; return (facture.montantPaye || 0) / facture.montantTTC * 100; }; const toolbarStartTemplate = () => (
); const toolbarEndTemplate = () => (
{facture?.statut !== 'PAYEE' && (
); if (loading) { return (
); } if (error || !facture) { return (

Facture introuvable

{error || 'La facture demandée n\'existe pas'}

); } return (
{/* En-tête de la facture */}

Facture #{facture.numero}

{facture.objet}

{formatCurrency(facture.montantTTC)}
HT: {formatCurrency(facture.montantHT)}
{facture.montantPaye && facture.montantPaye > 0 && (
Payé: {formatCurrency(facture.montantPaye)}
)}
{/* Barre de progression du paiement */} {facture.montantPaye && facture.montantPaye > 0 && (
Progression du paiement {Math.round(calculateProgress())}%
Payé: {formatCurrency(facture.montantPaye)} Restant: {formatCurrency(facture.montantTTC - facture.montantPaye)}
)}
Informations générales

{formatDate(facture.dateEmission)}

{formatDate(facture.dateEcheance)}

{typeof facture.client === 'string' ? facture.client : facture.client?.nom}

{facture.devis && (

)}
Détails financiers

{formatCurrency(facture.montantHT)}

{formatCurrency(facture.montantTTC - facture.montantHT)}

{formatCurrency(facture.montantTTC)}

{facture.montantPaye && (

{formatCurrency(facture.montantPaye)}

)}
{facture.description && ( <>
Description

{facture.description}

)}
{/* Lignes de la facture */} {facture.lignes && facture.lignes.length > 0 && (
rowData.quantite?.toLocaleString('fr-FR')} /> formatCurrency(rowData.prixUnitaire)} /> formatCurrency(rowData.montantHT)} />
)} {/* Historique des paiements */}
0 ? [{ status: facture.statut === 'PAYEE' ? 'Payée intégralement' : 'Paiement partiel', date: new Date(), icon: 'pi pi-money-bill', color: facture.statut === 'PAYEE' ? '#4CAF50' : '#FF9800', details: `Montant: ${formatCurrency(facture.montantPaye)}` }] : []), ...(new Date(facture.dateEcheance) < new Date() && facture.statut !== 'PAYEE' ? [{ status: 'Échue', date: facture.dateEcheance, icon: 'pi pi-exclamation-triangle', color: '#F44336' }] : []) ]} opposite={(item) => formatDate(item.date)} content={(item) => (
{item.details && (
{item.details}
)}
)} />
); }; export default FactureDetailPage;