From 0e81fbaf411c90ccc3ac622195cc184bbfaef6b2 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Mon, 1 Sep 2025 12:44:41 +0000 Subject: [PATCH] Add a waiting modal and timeout for webhook processing Introduce a waiting modal with a countdown timer for webhook processing, handle request timeouts with an AbortController, and improve error reporting for webhook failures. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 98f01874-e00c-4bbe-9d71-b0b338001848 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/98f01874-e00c-4bbe-9d71-b0b338001848/NGEmabJ --- client/src/pages/BLReconciliation.tsx | 122 +++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/client/src/pages/BLReconciliation.tsx b/client/src/pages/BLReconciliation.tsx index 8820d58..bc1a6ab 100644 --- a/client/src/pages/BLReconciliation.tsx +++ b/client/src/pages/BLReconciliation.tsx @@ -57,6 +57,11 @@ export default function BLReconciliation() { const [selectedFile, setSelectedFile] = useState(null); const [isUploading, setIsUploading] = useState(false); + // État pour le modal d'attente du webhook + const [showWaitingModal, setShowWaitingModal] = useState(false); + const [processingSeconds, setProcessingSeconds] = useState(0); + const [processingTimeout, setProcessingTimeout] = useState(null); + // État pour le système de vérification de facture const [verificationResults, setVerificationResults] = useState>({}); const [verifyingDeliveries, setVerifyingDeliveries] = useState>(new Set()); @@ -349,6 +354,29 @@ export default function BLReconciliation() { setIsUploading(false); }; + const handleCloseWaitingModal = () => { + setShowWaitingModal(false); + setProcessingSeconds(0); + if (processingTimeout) { + clearTimeout(processingTimeout); + setProcessingTimeout(null); + } + }; + + const startProcessingTimer = () => { + setProcessingSeconds(0); + const interval = setInterval(() => { + setProcessingSeconds(prev => { + if (prev >= 60) { + clearInterval(interval); + return 60; + } + return prev + 1; + }); + }, 1000); + setProcessingTimeout(interval); + }; + const handleFileChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file && file.type === 'application/pdf') { @@ -381,7 +409,11 @@ export default function BLReconciliation() { return; } + // Fermer le modal de sélection et ouvrir le modal d'attente + setShowInvoiceModal(false); + setShowWaitingModal(true); setIsUploading(true); + startProcessingTimer(); try { const formData = new FormData(); @@ -390,27 +422,51 @@ export default function BLReconciliation() { formData.append('blNumber', selectedDeliveryForInvoice.blNumber || ''); formData.append('type', 'Facture'); + // Créer un AbortController pour gérer le timeout + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 60000); // 60 secondes + const response = await fetch(selectedDeliveryForInvoice.group.webhookUrl, { method: 'POST', body: formData, + signal: controller.signal, }); + clearTimeout(timeoutId); + if (!response.ok) { throw new Error(`Erreur ${response.status}: ${response.statusText}`); } + handleCloseWaitingModal(); + toast({ title: "Succès", - description: "Facture envoyée avec succès via le webhook", + description: "Facture traitée avec succès via le webhook", }); - handleCloseInvoiceModal(); + // Reset des données + setSelectedDeliveryForInvoice(null); + setSelectedFile(null); + } catch (error: any) { + handleCloseWaitingModal(); + + let errorMessage = "Impossible d'envoyer la facture"; + if (error.name === 'AbortError') { + errorMessage = "Le traitement a pris trop de temps (timeout de 60 secondes)"; + } else if (error.message) { + errorMessage = `Impossible d'envoyer la facture: ${error.message}`; + } + toast({ title: "Erreur", - description: `Impossible d'envoyer la facture: ${error.message}`, + description: errorMessage, variant: "destructive", }); + + // Réouvrir le modal de sélection en cas d'erreur + setShowInvoiceModal(true); } finally { setIsUploading(false); } @@ -1171,6 +1227,66 @@ export default function BLReconciliation() { + + {/* Modal d'attente pour le traitement du webhook */} + {}}> + + + + + Traitement en cours + + +
+
+
+
+
+ {processingSeconds}s +
+
+ +
+

+ Traitement de votre facture en cours... +

+

+ Le workflow peut prendre jusqu'à 1 minute. +
+ Veuillez patienter. +

+
+ +
+
+
+ +
+ {processingSeconds < 60 ? `${60 - processingSeconds}s restantes (max)` : 'Finalisation...'} +
+
+ + {selectedDeliveryForInvoice && ( +
+
+
+ {selectedDeliveryForInvoice.supplier?.name} +
+
+ BL: {selectedDeliveryForInvoice.blNumber || 'Non renseigné'} +
+
+ Fichier: {selectedFile?.name} +
+
+
+ )} +
+
+
); } \ No newline at end of file