'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 { InputTextarea } from 'primereact/inputtextarea'; import { Dropdown } from 'primereact/dropdown'; import { Calendar } from 'primereact/calendar'; 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 { Timeline } from 'primereact/timeline'; import { Tag } from 'primereact/tag'; import { Badge } from 'primereact/badge'; import { Dialog } from 'primereact/dialog'; import { Checkbox } from 'primereact/checkbox'; import { factureService } from '../../../../../services/api'; import { formatDate, formatCurrency } from '../../../../../utils/formatters'; import type { Facture } from '../../../../../types/btp'; import { StatutFacture } from '../../../../../types/btp'; interface Relance { id: string; type: 'EMAIL' | 'COURRIER' | 'TELEPHONE' | 'SMS'; niveau: number; dateEnvoi: Date; destinataire: string; objet: string; message: string; statut: 'ENVOYEE' | 'LUE' | 'REPONDUE' | 'ECHEC'; reponse?: string; dateReponse?: Date; } interface RelanceTemplate { id: string; nom: string; type: 'EMAIL' | 'COURRIER' | 'TELEPHONE' | 'SMS'; niveau: number; objet: string; message: string; delaiJours: number; } const FactureRelancePage = () => { const params = useParams(); const router = useRouter(); const toast = useRef(null); const [facture, setFacture] = useState(null); const [relances, setRelances] = useState([]); const [templates, setTemplates] = useState([]); const [loading, setLoading] = useState(true); const [sending, setSending] = useState(false); const [showRelanceDialog, setShowRelanceDialog] = useState(false); const [nouvelleRelance, setNouvelleRelance] = useState({ type: 'EMAIL' as 'EMAIL' | 'COURRIER' | 'TELEPHONE' | 'SMS', destinataire: '', objet: '', message: '', dateEnvoi: new Date(), utiliserTemplate: false, templateId: '' }); const factureId = params.id as string; const typeOptions = [ { label: 'Email', value: 'EMAIL', icon: 'pi pi-envelope' }, { label: 'Courrier', value: 'COURRIER', icon: 'pi pi-send' }, { label: 'Téléphone', value: 'TELEPHONE', icon: 'pi pi-phone' }, { label: 'SMS', value: 'SMS', icon: 'pi pi-mobile' } ]; useEffect(() => { loadData(); }, [factureId]); const loadData = async () => { try { setLoading(true); // Charger la facture const factureResponse = await factureService.getById(factureId); setFacture(factureResponse); // TODO: Charger les relances et templates depuis l'API // const relancesResponse = await factureService.getRelances(factureId); // const templatesResponse = await factureService.getRelanceTemplates(); // Données simulées pour la démonstration const mockRelances: Relance[] = [ { id: '1', type: 'EMAIL', niveau: 1, dateEnvoi: new Date('2024-03-01'), destinataire: 'client@example.com', objet: 'Rappel - Facture en attente de paiement', message: 'Nous vous rappelons que votre facture est en attente de paiement...', statut: 'LUE' }, { id: '2', type: 'TELEPHONE', niveau: 2, dateEnvoi: new Date('2024-03-15'), destinataire: '01 23 45 67 89', objet: 'Appel de relance', message: 'Appel téléphonique pour relance de paiement', statut: 'REPONDUE', reponse: 'Client confirme le paiement sous 48h', dateReponse: new Date('2024-03-15') } ]; const mockTemplates: RelanceTemplate[] = [ { id: '1', nom: 'Première relance aimable', type: 'EMAIL', niveau: 1, objet: 'Rappel - Facture #{numero} en attente de paiement', message: 'Madame, Monsieur,\n\nNous vous rappelons que votre facture #{numero} d\'un montant de {montant} est en attente de paiement depuis le {dateEcheance}.\n\nMerci de bien vouloir régulariser cette situation dans les meilleurs délais.\n\nCordialement,', delaiJours: 7 }, { id: '2', nom: 'Relance ferme', type: 'COURRIER', niveau: 2, objet: 'Mise en demeure - Facture #{numero}', message: 'Madame, Monsieur,\n\nMalgré notre précédent rappel, votre facture #{numero} d\'un montant de {montant} demeure impayée.\n\nNous vous mettons en demeure de procéder au règlement sous 8 jours, faute de quoi nous nous verrons contraints d\'engager des poursuites.\n\nCordialement,', delaiJours: 15 } ]; setRelances(mockRelances); setTemplates(mockTemplates); // Pré-remplir le destinataire if (factureResponse.client) { const client = factureResponse.client; setNouvelleRelance(prev => ({ ...prev, destinataire: typeof client === 'string' ? client : client.email || client.nom })); } } 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 handleTemplateChange = (templateId: string) => { const template = templates.find(t => t.id === templateId); if (template && facture) { setNouvelleRelance(prev => ({ ...prev, templateId, type: template.type, objet: template.objet .replace('{numero}', facture.numero) .replace('{montant}', formatCurrency(facture.montantTTC)), message: template.message .replace('{numero}', facture.numero) .replace('{montant}', formatCurrency(facture.montantTTC)) .replace('{dateEcheance}', formatDate(facture.dateEcheance)) })); } }; const handleSendRelance = async () => { try { setSending(true); if (!nouvelleRelance.destinataire || !nouvelleRelance.objet || !nouvelleRelance.message) { toast.current?.show({ severity: 'warn', summary: 'Attention', detail: 'Veuillez remplir tous les champs obligatoires' }); return; } // TODO: Appel API pour envoyer la relance // await factureService.sendRelance(factureId, nouvelleRelance); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Relance envoyée avec succès' }); setShowRelanceDialog(false); loadData(); } catch (error) { console.error('Erreur lors de l\'envoi:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Erreur lors de l\'envoi de la relance' }); } finally { setSending(false); } }; const getStatutSeverity = (statut: string) => { switch (statut) { case 'ENVOYEE': return 'info'; case 'LUE': return 'warning'; case 'REPONDUE': return 'success'; case 'ECHEC': return 'danger'; default: return 'info'; } }; const getTypeIcon = (type: string) => { switch (type) { case 'EMAIL': return 'pi pi-envelope'; case 'COURRIER': return 'pi pi-send'; case 'TELEPHONE': return 'pi pi-phone'; case 'SMS': return 'pi pi-mobile'; default: return 'pi pi-circle'; } }; const getTypeColor = (type: string) => { switch (type) { case 'EMAIL': return '#3B82F6'; case 'COURRIER': return '#8B5CF6'; case 'TELEPHONE': return '#10B981'; case 'SMS': return '#F59E0B'; default: return '#6B7280'; } }; const toolbarStartTemplate = () => (
); const toolbarEndTemplate = () => (
); if (loading) { return (
); } if (!facture) { return (

Facture introuvable

La facture demandée n'existe pas

); } return (
{/* Informations de la facture */}

Relances - Facture #{facture.numero}

{facture.objet}

{formatCurrency(facture.montantTTC - (facture.montantPaye || 0))}
Montant en retard
Échéance: {formatDate(facture.dateEcheance)}
Retard: {Math.ceil((new Date().getTime() - new Date(facture.dateEcheance).getTime()) / (1000 * 60 * 60 * 24))} jours
{/* Historique des relances */}
{relances.length > 0 ? ( (
{formatDate(item.dateEnvoi)}
{item.destinataire}
)} content={(item) => (
{item.objet}
{item.message.length > 100 ? `${item.message.substring(0, 100)}...` : item.message }
{item.reponse && (
Réponse ({formatDate(item.dateReponse!)})
{item.reponse}
)}
)} marker={(item) => ( )} /> ) : (

Aucune relance envoyée pour cette facture

)}
{/* Statistiques et actions */}
{relances.length}
Relances envoyées
{relances.filter(r => r.statut === 'REPONDUE').length}
Réponses reçues
{Math.ceil((new Date().getTime() - new Date(facture.dateEcheance).getTime()) / (1000 * 60 * 60 * 24))}
Jours de retard
Actions recommandées
{/* Dialog de nouvelle relance */} setShowRelanceDialog(false)} style={{ width: '800px' }} footer={
} >
setNouvelleRelance(prev => ({ ...prev, utiliserTemplate: e.checked || false, templateId: e.checked ? templates[0]?.id || '' : '' }))} />
{nouvelleRelance.utiliserTemplate && (
({ label: t.nom, value: t.id }))} onChange={(e) => handleTemplateChange(e.value)} className="w-full" placeholder="Sélectionner un template" />
)}
setNouvelleRelance(prev => ({ ...prev, type: e.value }))} className="w-full" itemTemplate={(option) => (
{option.label}
)} />
setNouvelleRelance(prev => ({ ...prev, dateEnvoi: e.value || new Date() }))} className="w-full" dateFormat="dd/mm/yy" showTime />
setNouvelleRelance(prev => ({ ...prev, destinataire: e.target.value }))} className="w-full" rows={1} />
setNouvelleRelance(prev => ({ ...prev, objet: e.target.value }))} className="w-full" rows={2} />
setNouvelleRelance(prev => ({ ...prev, message: e.target.value }))} className="w-full" rows={8} />
); }; export default FactureRelancePage;