import { useState, useRef } from 'react'; import { Emailsend } from '../../../../Features/PurchaseOrder/PurchaseOrder'; import { blobToBase64, encryptObject, pdfDiv, } from '../../../../Services/Others'; import { PrintStyleFunction } from '../../../paymentpdfPage/PrintStyleFunction'; import { PDFDocument } from 'pdf-lib'; import { PublicQrCodepost } from '../../../../Features/ConfigMasterPage/ConfigMasterPage'; import { renderToStaticMarkup } from 'react-dom/server'; const MainHomeUrl = import.meta.env.ENV_MAIN_BASE_URL; const uploadApiUrl = import.meta.env.ENV_IMAGE_UPLOAD_API_URL; // Create a secure blob URL creator that works in all environments const createSecureBlobUrl = (blob) => { try { return URL.createObjectURL(blob); } catch (error) { console.warn( 'Standard blob URL creation failed, using alternative approach' ); return window.URL.createObjectURL(blob); } }; // Revoke blob URL safely const revokeSecureBlobUrl = (url) => { if (url && url.startsWith('blob:')) { try { URL.revokeObjectURL(url); } catch (error) { console.warn('Failed to revoke blob URL:', error); } } }; // Merge multiple pdf blobs into one const mergePdfBlobs = async (blobs) => { const mergedPdf = await PDFDocument.create(); for (const blob of blobs) { const pdfBytes = await blob.arrayBuffer(); const pdf = await PDFDocument.load(pdfBytes); const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices()); copiedPages.forEach((page) => mergedPdf.addPage(page)); } const mergedBytes = await mergedPdf.save(); return new Blob([mergedBytes], { type: 'application/pdf' }); }; export const MobileMultiPdfPrint = async ({ printerTemplateStyle = 'Style 13', printDatas = {}, PrintOrderDetails = [], setPrintOrderDetails = () => {}, PrintComing = '', emailId = '', dispatch, UserId = '', onProgress = () => {}, returnBlob = false, }) => { try { const style = await PrintStyleFunction(printerTemplateStyle, 'Sales'); const stylesMap = { 'Style 1': 'PrintStyle1', 'Style 2': 'PrintStyle2', 'Style 3': 'PrintStyle3', 'Style 4': 'PrintStyle4', 'Style 5': 'PrintStyle5', 'Style 6': 'PrintStyle6', 'Style 7': 'PrintStyle7', 'Style 8': 'PrintStyle8', 'Style 9': 'PrintStyle9', 'Style 10': 'PrintStyle10', 'Style 11': 'PrintStyle11', 'Style 12': 'PrintStyle12', 'Style 13': 'RePrint', A4: 'PrintStyleA4', A5: 'PrintStyleA5', A4Standard: 'A4Standard', TaxInvoice: 'TaxInvoice', }; const selectedStyle = stylesMap[printerTemplateStyle] || 'RePrint'; const Printsize = printDatas?.PageSize || 'A4'; const totalOrders = PrintOrderDetails.length; let allBlobs = []; // 🔥 LOOP EACH INVOICE (MAIN FIX) for (let i = 0; i < totalOrders; i++) { const element = document.getElementById( `${selectedStyle}-${i}` ); if (!element) { console.warn('⚠️ Element not found:', `${selectedStyle}-${i}`); continue; } // 🔥 TEMP WRAPPER (IMPORTANT) const wrapper = document.createElement('div'); wrapper.id = `temp-${i}`; wrapper.style.width = '794px'; wrapper.style.background = '#fff'; wrapper.innerHTML = ` ${style} ${element.innerHTML} `; document.body.appendChild(wrapper); try { // 👉 ONE invoice → ONE PDF const blob = await pdfDiv(wrapper.id); allBlobs.push(blob); } catch (err) { console.error('PDF error:', err); } document.body.removeChild(wrapper); // 🔥 Progress update const progress = Math.round(((i + 1) / totalOrders) * 100); onProgress(progress); // 🔥 small delay for stability (important for large data) await new Promise((r) => setTimeout(r, 5)); } // 🔥 MERGE ALL PDFs const combinedPdfBlob = await mergePdfBlobs(allBlobs); const base64Pdf = await blobToBase64(combinedPdfBlob); // 🔥 DOWNLOAD if (PrintComing === 'download') { const blobUrl = createSecureBlobUrl(combinedPdfBlob); const link = document.createElement('a'); link.href = blobUrl; link.download = 'Receipts.pdf'; document.body.appendChild(link); link.click(); setTimeout(() => { document.body.removeChild(link); revokeSecureBlobUrl(blobUrl); }, 100); } // 🔥 RETURN BLOB if (returnBlob && PrintComing === 'download') { setPrintOrderDetails([]); return { success: true, pdfBlob: combinedPdfBlob }; } // 🔥 WHATSAPP if (PrintComing === 'whatsapp') { const orderIdsArray = PrintOrderDetails.map((row) => row?.OrderId).filter(Boolean); if (orderIdsArray.length === 0) return; const encrypted = encryptObject(orderIdsArray); const postData = { Url: encrypted, CreatedBy: UserId, }; try { const res = await dispatch(PublicQrCodepost(postData)).unwrap(); const urlData = res?.data?.ReferenceNo || res?.ReferenceNo; if (!urlData) return; const documentUrl = `${MainHomeUrl}viewbill?code=${urlData}`; const waUrl = 'https://web.whatsapp.com/send?text=' + encodeURIComponent('Here are your receipts 👉 ' + documentUrl); window.open(waUrl, '_blank'); } catch (err) { console.error('❌ WhatsApp error:', err); } } // 🔥 EMAIL if (PrintComing === 'email') { try { const payload = { fileBlob: combinedPdfBlob, toEmail: emailId, type: 'Sales', messageTemplatesList: [], }; const res = await dispatch(Emailsend(payload))?.unwrap(); return res; } catch (err) { console.error('❌ Email error:', err); } } // 🔥 PRINT VIEW if (!['download', 'whatsapp', 'email'].includes(PrintComing)) { const blobUrl = createSecureBlobUrl(combinedPdfBlob); const newWindow = window.open('', '_blank'); if (newWindow) { newWindow.document.write(` `); newWindow.document.close(); } else { window.location.href = blobUrl; } const intentUrl = 'intent://open?' + 'filename=' + encodeURIComponent('Receipts.pdf') + '&size=' + combinedPdfBlob.size + '&type=application/pdf' + '&data=' + encodeURIComponent(base64Pdf) + '&PrintTypeS=' + encodeURIComponent(Printsize) + '#Intent;scheme=pozoprinter;package=com.example.pozoprinter;end'; setTimeout(() => { try { window.location.href = intentUrl; } catch {console.log("some errors")} }, 500); } // 🔥 CLEANUP setPrintOrderDetails([]); return { success: true, message: 'PDF processed successfully' }; } catch (error) { console.error('MobileMultiPdfPrint error:', error); return { success: false, message: error.message }; } }; // export const MobileMultiPdfPrint = async ({ // printerTemplateStyle = 'Style 13', // printDatas = {}, // PrintOrderDetails = [], // setPrintOrderDetails = () => {}, // PrintComing = '', // emailId = '', // dispatch, // UserId = '', // onProgress = () => {}, // returnBlob = false, // }) => { // try { // const style = await PrintStyleFunction(printerTemplateStyle, 'Sales'); // const stylesMap = { // 'Style 1': 'PrintStyle1', // 'Style 2': 'PrintStyle2', // 'Style 3': 'PrintStyle3', // 'Style 4': 'PrintStyle4', // 'Style 5': 'PrintStyle5', // 'Style 6': 'PrintStyle6', // 'Style 7': 'PrintStyle7', // 'Style 8': 'PrintStyle8', // 'Style 9': 'PrintStyle9', // 'Style 10': 'PrintStyle10', // 'Style 11': 'PrintStyle11', // 'Style 12': 'PrintStyle12', // 'Style 13': 'RePrint', // A4: 'PrintStyleA4', // A5: 'PrintStyleA5', // A4Standard: 'A4Standard', // TaxInvoice: 'TaxInvoice', // }; // const selectedStyle = stylesMap[printerTemplateStyle] || 'RePrint'; // const Printsize = printDatas?.PageSize || 'A4'; // // Create or clear the container // let container = document.getElementById('print-merged'); // if (!container) { // container = document.createElement('div'); // container.id = 'print-merged'; // container.style.display = 'none'; // document.body.appendChild(container); // } else { // container.innerHTML = ''; // } // // Process in batches for large files // const BATCH_SIZE = 5; // const totalOrders = PrintOrderDetails.length; // let processedOrders = 0; // let allBlobs = []; // for (let i = 0; i < totalOrders; i += BATCH_SIZE) { // const batch = PrintOrderDetails.slice(i, i + BATCH_SIZE); // // Clear container for each batch // container.innerHTML = ''; // // Process each order in the current batch // batch.forEach((_, index) => { // const globalIndex = i + index; // const element = document.getElementById( // `${selectedStyle}-${globalIndex}` // ); // if (element) { // const cloned = element.cloneNode(true); // // Add page break between orders (except the last one) // if (globalIndex < totalOrders - 1) { // const pageBreak = document.createElement('div'); // pageBreak.style.pageBreakAfter = 'always'; // container.appendChild(cloned); // container.appendChild(pageBreak); // } else { // container.appendChild(cloned); // } // } else { // console.warn( // '⚠️ Element not found:', // `${selectedStyle}-${globalIndex}` // ); // } // }); // // Generate PDF for this batch // try { // const pdfBlob = await pdfDiv('print-merged', style); // allBlobs.push(pdfBlob); // processedOrders += batch.length; // const progress = Math.round((processedOrders / totalOrders) * 100); // onProgress(progress); // } catch (error) { // console.error('Error generating PDF batch:', error); // throw new Error( // `Failed to generate PDF for batch starting at index ${i}` // ); // } // } // // ✅ Merge all PDF blobs into one // const combinedPdfBlob = await mergePdfBlobs(allBlobs); // const base64Pdf = await blobToBase64(combinedPdfBlob); // // Handle different print actions // if (PrintComing === 'download') { // const blobUrl = createSecureBlobUrl(combinedPdfBlob); // const link = document.createElement('a'); // link.href = blobUrl; // link.download = 'Receipts.pdf'; // document.body.appendChild(link); // link.click(); // setTimeout(() => { // document.body.removeChild(link); // revokeSecureBlobUrl(blobUrl); // }, 100); // } // // Return blob if requested (after download completes) // if (returnBlob && PrintComing === 'download') { // setPrintOrderDetails([]); // if (container) { // document.body.removeChild(container); // } // return { success: true, pdfBlob: combinedPdfBlob }; // } // // if (PrintComing === "whatsapp") { // // const orderIds = PrintOrderDetails.map((row) => row?.OrderId).filter(Boolean); // // const documentUrl = `${MainHomeUrl}viewbill?code=${orderIds}`; // // const waUrl = // // "https://web.whatsapp.com/send?text=" + // // encodeURIComponent("Here are your receipts 👉 " + documentUrl); // // window.open(waUrl, "_blank"); // // } // if (PrintComing === 'whatsapp') { // const orderIdsArray = PrintOrderDetails.map((row) => row?.OrderId).filter( // Boolean // ); // if (orderIdsArray.length === 0) { // console.warn('⚠️ No order IDs found for WhatsApp sharing.'); // return; // } // // 2️⃣ Encrypt order IDs // const encrypted = encryptObject(orderIdsArray); // // 3️⃣ Prepare payload for backend // const postData = { // Url: encrypted, // CreatedBy: UserId, // Make sure UserId is passed correctly to your function // }; // try { // // 4️⃣ Call backend to get a ReferenceNo // const res = await dispatch(PublicQrCodepost(postData)).unwrap(); // console.log('Backend response:', res); // // 5️⃣ Extract ReferenceNo (adjust based on your backend response structure) // // Example: it might be res.data.ReferenceNo or res.ReferenceNo // const urlData = res?.data?.ReferenceNo || res?.ReferenceNo; // if (!urlData) { // console.error('❌ No ReferenceNo returned from backend'); // return; // } // // 6️⃣ Build the shareable URL // const documentUrl = `${MainHomeUrl}viewbill?code=${urlData}`; // // 7️⃣ Open WhatsApp Web with URL // const waUrl = // 'https://web.whatsapp.com/send?text=' + // encodeURIComponent('Here are your receipts 👉 ' + documentUrl); // window.open(waUrl, '_blank'); // } catch (err) { // console.error('❌ WhatsApp sharing failed:', err); // } // } // if (PrintComing === 'email') { // try { // const payload = { // fileBlob: combinedPdfBlob, // toEmail: emailId, // type: 'Sales', // messageTemplatesList: [], // }; // const res = await dispatch(Emailsend(payload))?.unwrap(); // console.log('✅ Email sent response:', res?.data || res); // return res; // } catch (err) { // console.error('❌ Email error:', err); // } // } // if (!['download', 'whatsapp', 'email'].includes(PrintComing)) { // const blobUrl = createSecureBlobUrl(combinedPdfBlob); // const newWindow = window.open('', '_blank'); // if (newWindow) { // newWindow.document.write(` // // // Receipts // // // // // // // // `); // newWindow.document.close(); // } else { // window.location.href = blobUrl; // } // // For mobile intent URL // const intentUrl = // 'intent://open?' + // 'filename=' + // encodeURIComponent('Receipts.pdf') + // '&size=' + // combinedPdfBlob.size + // '&type=application/pdf' + // '&data=' + // encodeURIComponent(base64Pdf) + // '&PrintTypeS=' + // encodeURIComponent(Printsize) + // '&PrintTypeE' + // '#Intent;scheme=pozoprinter;package=com.example.pozoprinter;end'; // setTimeout(() => { // try { // window.location.href = intentUrl; // } catch (e) { // console.warn('Could not open intent URL:', e); // } // }, 500); // } // // Clean up // setPrintOrderDetails([]); // if (container) { // document.body.removeChild(container); // } // return { success: true, message: 'PDF processed successfully' }; // } catch (error) { // console.error('MobileMultiPdfPrint error:', error); // return { success: false, message: error.message }; // } // }; // Progress component to show processing status export const PdfProcessingProgress = ({ progress, isProcessing }) => { if (!isProcessing) return null; return (

Processing PDFs

{progress}% Complete

); }; export const MobileMultiCreditPdfPrint = async ({ PrintOrderDetails = [], BSCreditCustomerPrint, style, PrintComing = '', emailId = '', dispatch, UserId = '', onProgress = () => {}, BATCH_SIZE = 5, }) => { if (!BSCreditCustomerPrint) { throw new Error('BSCreditCustomerPrint component is required'); } // Helper: wait for images & fonts in a container const waitForImagesAndFonts = (container, timeout = 7000) => new Promise((resolve) => { // images const imgs = Array.from(container.querySelectorAll('img')); let remaining = imgs.length; if (remaining === 0) { // still ensure fonts ready if (document.fonts && document.fonts.ready) { document.fonts.ready.then(() => resolve()).catch(() => resolve()); } else resolve(); return; } const timer = setTimeout(() => { clearTimeout(timer); resolve(); }, timeout); imgs.forEach((img) => { if (img.complete) { remaining--; if (remaining === 0) { clearTimeout(timer); // fonts: if (document.fonts && document.fonts.ready) { document.fonts.ready.then(() => resolve()).catch(() => resolve()); } else resolve(); } } else { img.addEventListener( 'load', () => { remaining--; if (remaining === 0) { clearTimeout(timer); if (document.fonts && document.fonts.ready) { document.fonts.ready .then(() => resolve()) .catch(() => resolve()); } else resolve(); } }, { once: true } ); img.addEventListener( 'error', () => { remaining--; if (remaining === 0) { clearTimeout(timer); if (document.fonts && document.fonts.ready) { document.fonts.ready .then(() => resolve()) .catch(() => resolve()); } else resolve(); } }, { once: true } ); } }); }); // Fallback mergePdfBlobs using pdf-lib (client-side) const mergePdfBlobsFallback = async (blobs) => { if (!blobs || blobs.length === 0) { return new Blob([], { type: 'application/pdf' }); } if (blobs.length === 1) return blobs[0]; const mergedPdf = await PDFDocument.create(); for (const blob of blobs) { const arrayBuffer = await blob.arrayBuffer(); const donorPdf = await PDFDocument.load(arrayBuffer); const copiedPages = await mergedPdf.copyPages( donorPdf, donorPdf.getPageIndices() ); copiedPages.forEach((p) => mergedPdf.addPage(p)); } const mergedBytes = await mergedPdf.save(); return new Blob([mergedBytes], { type: 'application/pdf' }); }; const blobToBase64 = (blob) => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result.split(',')[1]); // base64 without prefix reader.onerror = reject; reader.readAsDataURL(blob); }); // create container or ensure empty let printRootContainer = document.getElementById('print-merged-react'); if (printRootContainer) { printRootContainer.innerHTML = ''; } else { printRootContainer = document.createElement('div'); printRootContainer.id = 'print-merged-react'; printRootContainer.style.display = 'none'; document.body.appendChild(printRootContainer); } const total = PrintOrderDetails.length; let allBlobs = []; let processedVisible = 0; try { for (let i = 0; i < total; i += BATCH_SIZE) { const batch = PrintOrderDetails.slice(i, i + BATCH_SIZE); // clear container for each batch printRootContainer.innerHTML = ''; // Render each BSCreditCustomerPrint into its own div const roots = []; for (let idx = 0; idx < batch.length; idx++) { const globalIndex = i + idx; const wrapper = document.createElement('div'); wrapper.id = `Credit-customer-${globalIndex}`; const html = renderToStaticMarkup( ); wrapper.innerHTML = html; printRootContainer.appendChild(wrapper); // add page break if needed if (globalIndex < total - 1) { const pb = document.createElement('div'); pb.style.pageBreakAfter = 'always'; printRootContainer.appendChild(pb); } roots.push(printRootContainer); } await new Promise((res) => setTimeout(res, 120)); // small tick await waitForImagesAndFonts(printRootContainer, 8000); const batchContainerId = `print-merged-batch-${i}`; let batchContainer = document.getElementById(batchContainerId); if (!batchContainer) { batchContainer = document.createElement('div'); batchContainer.id = batchContainerId; batchContainer.style.display = 'none'; document.body.appendChild(batchContainer); } batchContainer.innerHTML = `${style}${printRootContainer.innerHTML}`; const pdfBlob = await pdfDiv(batchContainerId, style); allBlobs.push(pdfBlob); roots.forEach((r) => { try { r.unmount(); } catch (e) { // ignore } }); // cleanup batch container try { if (batchContainer && batchContainer.parentElement) { batchContainer.parentElement.removeChild(batchContainer); } } catch (e) { /* ignore */ } // progress processedVisible += batch.length; onProgress(Math.round((processedVisible / total) * 100)); } // merge blobs - use existing merge function if available, otherwise fallback const combinedPdfBlob = typeof mergePdfBlobs === 'function' ? await mergePdfBlobs(allBlobs) : await mergePdfBlobsFallback(allBlobs); const base64Pdf = await blobToBase64(combinedPdfBlob); // Action handlers if (PrintComing === 'download') { const blobUrl = typeof createSecureBlobUrl === 'function' ? createSecureBlobUrl(combinedPdfBlob) : URL.createObjectURL(combinedPdfBlob); const link = document.createElement('a'); link.href = blobUrl; link.download = 'Receipts.pdf'; document.body.appendChild(link); link.click(); setTimeout(() => { document.body.removeChild(link); if (typeof revokeSecureBlobUrl === 'function') revokeSecureBlobUrl(blobUrl); else URL.revokeObjectURL(blobUrl); }, 300); return { success: true }; } if (PrintComing === 'whatsapp') { const orderIdsArray = PrintOrderDetails.map((r) => r?.receiptNo).filter( Boolean ); if (orderIdsArray.length === 0) { console.warn('No order ids for whatsapp'); return { success: false, message: 'No orders' }; } const encrypted = encryptObject(orderIdsArray); const postData = { Url: encrypted, CreatedBy: UserId }; try { const res = await dispatch(PublicQrCodepost(postData)).unwrap(); const urlData = res?.data?.ReferenceNo || res?.ReferenceNo; if (!urlData) throw new Error('No ReferenceNo from backend'); const documentUrl = `${MainHomeUrl}viewbill?code=${urlData}`; const waUrl = 'https://web.whatsapp.com/send?text=' + encodeURIComponent('Here are your receipts 👉 ' + documentUrl); window.open(waUrl, '_blank'); return { success: true }; } catch (err) { console.error('WhatsApp sharing failed', err); return { success: false, message: err?.message || String(err) }; } } if (PrintComing === 'email') { try { const payload = { fileBlob: combinedPdfBlob, toEmail: emailId, type: 'CreditReceipt', messageTemplatesList: [], }; const res = await dispatch(Emailsend(payload)).unwrap(); return { success: true, data: res }; } catch (err) { console.error('Email send failed', err); return { success: false, message: err?.message || String(err) }; } } // default: open viewer tab and attempt mobile intent const blobUrl = typeof createSecureBlobUrl === 'function' ? createSecureBlobUrl(combinedPdfBlob) : URL.createObjectURL(combinedPdfBlob); const newWindow = window.open('', '_blank'); if (newWindow) { newWindow.document.write(` Receipts `); newWindow.document.close(); } else { window.location.href = blobUrl; } // mobile intent (optional) const intentUrl = 'intent://open?' + 'filename=' + encodeURIComponent('Receipts.pdf') + '&size=' + combinedPdfBlob.size + '&type=application/pdf' + '&data=' + encodeURIComponent(base64Pdf) + '#Intent;scheme=pozoprinter;package=com.example.pozoprinter;end'; try { setTimeout(() => { try { window.location.href = intentUrl; } catch (e) { /* ignore */ } }, 500); } catch (e) { /* ignore */ } return { success: true }; } catch (err) { console.error('MobileMultiCreditPdfPrint error:', err); return { success: false, message: err?.message || String(err) }; } finally { // final cleanup try { // remove printRootContainer and any leftover child batch containers const root = document.getElementById('print-merged-react'); if (root && root.parentElement) root.parentElement.removeChild(root); // remove any batch containers (ids starting with print-merged-batch-) Array.from( document.querySelectorAll("[id^='print-merged-batch-']") ).forEach((el) => { try { el.parentElement.removeChild(el); } catch (e) {} }); } catch (e) { console.warn('Cleanup error', e); } } };