diff --git a/src/components/Dashboard/context/ApiServerContext.jsx b/src/components/Dashboard/context/ApiServerContext.jsx index cc5537b..a833604 100644 --- a/src/components/Dashboard/context/ApiServerContext.jsx +++ b/src/components/Dashboard/context/ApiServerContext.jsx @@ -859,7 +859,7 @@ const ApiServerProvider = ({ children }) => { } const fetchTemplatePDF = async (id, content, testObject, callback) => { - logger.debug('Fetching preview...') + logger.debug('Fetching pdf template...') if (socketRef.current && socketRef.current.connected) { return socketRef.current.emit( 'renderTemplatePDF', @@ -873,6 +873,38 @@ const ApiServerProvider = ({ children }) => { } } + const downloadTemplatePDF = async ( + id, + content, + object, + filename, + callback + ) => { + logger.debug('Downloading template PDF...') + + fetchTemplatePDF(id, content, object, (result) => { + logger.debug('Downloading template PDF result:', result) + if (result?.error) { + console.error(result.error) + if (callback) { + callback(result.error) + } + } else { + const pdfBlob = new Blob([result.pdf], { type: 'application/pdf' }) + const pdfUrl = URL.createObjectURL(pdfBlob) + const fileLink = document.createElement('a') + fileLink.href = pdfUrl + fileLink.setAttribute('download', `${filename}.pdf`) + document.body.appendChild(fileLink) + fileLink.click() + fileLink.parentNode.removeChild(fileLink) + if (callback) { + callback() + } + } + }) + } + const fetchHostOTP = async (id, callback) => { logger.debug('Fetching host OTP...') if (socketRef.current && socketRef.current.connected) { @@ -962,6 +994,22 @@ const ApiServerProvider = ({ children }) => { } } + // Sanitize a string so it is safe to use as a filename on most file systems + const formatFileName = (name) => { + if (!name || typeof name !== 'string') { + return '' + } + + // Remove characters that are problematic on most common file systems + const cleaned = name.replace(/[^a-zA-Z0-9.\-_\s]/g, '') + + // Normalize whitespace to single underscores + const normalized = cleaned.trim().replace(/\s+/g, '_') + + // Most file systems limit filenames to 255 characters + return normalized.slice(0, 255) + } + return ( { fetchTemplatePreview, fetchTemplatePDF, fetchNotes, + downloadTemplatePDF, fetchHostOTP, sendObjectAction, uploadFile, - flushFile + flushFile, + formatFileName }} > {contextHolder}