From 8e6eafd804ec62cc2b0e88dec758e46eb832bfe2 Mon Sep 17 00:00:00 2001 From: Krishna Das Date: Wed, 20 May 2026 23:44:00 +0530 Subject: [PATCH 1/2] fix(frontend): resolve test certificate reference error and api mismatch --- .../Form/CertificatesForm/SendCertificate.jsx | 33 ++++++++++--------- .../tools/certificateTools.js | 22 +++++++++++++ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx b/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx index f1a936e5..31f340a9 100644 --- a/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx +++ b/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx @@ -3,13 +3,13 @@ import { useParams } from "react-router-dom"; import { Button, Input } from "../../../../../components"; import { api } from "../../../../../services"; import * as XLSX from "xlsx"; -import { sendBatchMail } from "./tools/certificateTools"; -import { Alert, MicroLoading } from "../../../../../microInteraction"; import { getCertificatePreview, generatedAndSendCertificate, accessOrCreateEventByFormId, -} from "../CertificatesForm/tools/certificateTools"; + testCertificateSending, +} from "./tools/certificateTools"; +import { Alert, MicroLoading } from "../../../../../microInteraction"; import AuthContext from "../../../../../context/AuthContext.jsx"; const Checkbox = ({ id, checked, onCheckedChange }) => { @@ -284,20 +284,23 @@ const SendCertificate = () => { setSendingMail(true); try { - await sendBatchMail({ - batchSize: 1, - formId: eventId, + const eventData = await accessOrCreateEventByFormId( + eventId, + authCtx.token + ); + if (!eventData || !eventData.id) { + throw new Error("Event data retrieval failed"); + } + + const response = await testCertificateSending({ + eventId: eventData.id, + email: checkedAttendees[0].email, + name: checkedAttendees[0].name || "", subject: `[TEST] ${subject}`, - htmlContent: description, - recipients: [ - { - email: checkedAttendees[0].email, - name: checkedAttendees[0].name || "", - }, - ], + token: authCtx.token, }); - if (response.status === 200) { + if (response && response.status === 200) { setAlert({ type: "success", message: "Test mail sent successfully!", @@ -305,7 +308,7 @@ const SendCertificate = () => { duration: 3000, }); } else { - throw new Error(response.data?.error || "Failed to send test mail"); + throw new Error(response?.data?.error || "Failed to send test mail"); } } catch (error) { setAlert({ diff --git a/src/sections/Profile/Admin/Form/CertificatesForm/tools/certificateTools.js b/src/sections/Profile/Admin/Form/CertificatesForm/tools/certificateTools.js index 49614ce7..6e24a4ed 100644 --- a/src/sections/Profile/Admin/Form/CertificatesForm/tools/certificateTools.js +++ b/src/sections/Profile/Admin/Form/CertificatesForm/tools/certificateTools.js @@ -118,9 +118,31 @@ const generatedAndSendCertificate = async ({ } }; +const testCertificateSending = async ({ eventId, email, name, subject, token }) => { + try { + const response = await api.post( + "/api/certificate/testCertificateSending", + { + eventId, + email, + name, + subject, + }, + { + headers: { Authorization: `Bearer ${token}` }, + } + ); + return response; + } catch (error) { + console.error("Error sending test certificate:", error); + return error.response; + } +}; + export { accessOrCreateEventByFormId, getCertificatePreview, sendBatchMail, generatedAndSendCertificate, + testCertificateSending, }; From a73a1b890e3368b2b3b23fbcf46ac57ed1cd8ca1 Mon Sep 17 00:00:00 2001 From: Krishna Das Date: Wed, 20 May 2026 23:56:56 +0530 Subject: [PATCH 2/2] feat(frontend): add failed emails tracking panel with retry for certificate sending --- .../Form/CertificatesForm/SendCertificate.jsx | 110 +++++++++++++++++- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx b/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx index 31f340a9..178b4442 100644 --- a/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx +++ b/src/sections/Profile/Admin/Form/CertificatesForm/SendCertificate.jsx @@ -41,6 +41,7 @@ const SendCertificate = () => { const [fileUploading, setFileUploading] = useState(false); const [certificatePreview, setCertificatePreview] = useState("Loading..."); const [alert, setAlert] = useState(null); + const [failedEmails, setFailedEmails] = useState([]); useEffect(() => { const fetchCertificatePreview = async () => { @@ -211,6 +212,7 @@ const SendCertificate = () => { } setSendingMail(true); + setFailedEmails([]); try { const eventData = await accessOrCreateEventByFormId( @@ -248,13 +250,22 @@ const SendCertificate = () => { token: authCtx.token, }); - if (response?.status === 200 || response?.status === 207) { + if (response?.status === 200) { setAlert({ - type: response.status === 200 ? "success" : "warning", - message: response.data?.message || "Certificates processed.", + type: "success", + message: response.data?.message || "All certificates sent successfully!", position: "top-right", duration: 4000, }); + } else if (response?.status === 207) { + const failed = response.data?.failed || []; + setFailedEmails(failed); + setAlert({ + type: "warning", + message: response.data?.message || "Some certificates failed to send.", + position: "top-right", + duration: 5000, + }); } else { throw new Error(response?.data?.error || "Failed to send certificates"); } @@ -583,6 +594,99 @@ const SendCertificate = () => { + + {failedEmails.length > 0 && ( +
+
+

+ ⚠ Failed Emails ({failedEmails.length}) +

+
+ + +
+
+
+ {failedEmails.map((item, idx) => ( +
+ {item.email} + + {item.error || "Unknown error"} + +
+ ))} +
+
+ )} );