964 lines
29 KiB
JavaScript
964 lines
29 KiB
JavaScript
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';
|
||
import { downloadFile } from '../../../../utils/downloadFile';
|
||
|
||
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);
|
||
// }
|
||
const combinedPdfBlob = await mergePdfBlobs(allBlobs);
|
||
const base64Pdf = await blobToBase64(combinedPdfBlob);
|
||
|
||
// 🔥 DOWNLOAD
|
||
|
||
if (PrintComing === 'download') {
|
||
// ✅ Convert Blob → ArrayBuffer for downloadFile
|
||
const buffer = await combinedPdfBlob.arrayBuffer();
|
||
|
||
downloadFile(
|
||
buffer,
|
||
"Receipts.pdf",
|
||
"application/pdf",
|
||
(success) => {
|
||
if (!success) {
|
||
|
||
console.error('Failed to download the file. Please try again.');
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
// 🔥 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(`
|
||
<html>
|
||
<body style="margin:0">
|
||
<button onclick="window.print()"
|
||
style="position:fixed;top:10px;right:10px;">Print</button>
|
||
<iframe src="${blobUrl}" style="width:100%;height:100%;border:none"></iframe>
|
||
</body>
|
||
</html>
|
||
`);
|
||
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(`
|
||
// <html>
|
||
// <head>
|
||
// <title>Receipts</title>
|
||
// <style>
|
||
// body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #f0f0f0; }
|
||
// iframe { width: 100%; height: 100%; border: none; }
|
||
// .print-button { position: fixed; top: 20px; right: 20px; z-index: 1000; padding: 10px 15px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
||
// </style>
|
||
// </head>
|
||
// <body>
|
||
// <button class="print-button" onclick="window.print()">Print</button>
|
||
// <iframe src="${blobUrl}" type="application/pdf"></iframe>
|
||
// </body>
|
||
// </html>
|
||
// `);
|
||
// 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 (
|
||
<div
|
||
style={{
|
||
position: 'fixed',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
backgroundColor: 'rgba(0,0,0,0.7)',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
zIndex: 10999,
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
backgroundColor: 'white',
|
||
padding: '20px',
|
||
borderRadius: '8px',
|
||
textAlign: 'center',
|
||
minWidth: '300px',
|
||
}}
|
||
>
|
||
<h3>Processing PDFs</h3>
|
||
<div
|
||
style={{
|
||
width: '100%',
|
||
backgroundColor: '#f0f0f0',
|
||
borderRadius: '4px',
|
||
margin: '15px 0',
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
width: `${progress}%`,
|
||
height: '20px',
|
||
backgroundColor: '#4caf50',
|
||
borderRadius: '4px',
|
||
transition: 'width 0.3s',
|
||
}}
|
||
></div>
|
||
</div>
|
||
<p>{progress}% Complete</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
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(
|
||
<BSCreditCustomerPrint PrintDatas={batch[idx]} />
|
||
);
|
||
|
||
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 };
|
||
// }
|
||
const combinedPdfBlob =
|
||
typeof mergePdfBlobs === 'function'
|
||
? await mergePdfBlobs(allBlobs)
|
||
: await mergePdfBlobsFallback(allBlobs);
|
||
|
||
const base64Pdf = await blobToBase64(combinedPdfBlob);
|
||
|
||
// Action handlers
|
||
if (PrintComing === 'download') {
|
||
// ✅ Convert Blob → ArrayBuffer for downloadFile
|
||
const buffer = await combinedPdfBlob.arrayBuffer();
|
||
|
||
downloadFile(
|
||
buffer,
|
||
"Receipts.pdf",
|
||
"application/pdf",
|
||
(success) => {
|
||
if (!success) {
|
||
console.error('Failed to download the file. Please try again.');
|
||
}
|
||
}
|
||
);
|
||
|
||
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(`
|
||
<html>
|
||
<head><title>Receipts</title>
|
||
<style>
|
||
body{margin:0;background:#f0f0f0;height:100vh;display:flex;align-items:center;justify-content:center}
|
||
iframe{width:100%;height:100%;border:none}
|
||
.print-button{position:fixed;top:16px;right:16px;padding:10px 14px;background:#4CAF50;color:white;border:none;border-radius:6px;cursor:pointer;z-index:9999}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<button class="print-button" onclick="window.print()">Print</button>
|
||
<iframe src="${blobUrl}" type="application/pdf"></iframe>
|
||
</body>
|
||
</html>
|
||
`);
|
||
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);
|
||
}
|
||
}
|
||
};
|