import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import { Messages } from '../../../Components/Notifications/Messages'; import FormHeader from '../../PageComponents/FormHeader'; import PublicQrCodeShare from '../PublicQrCodeShare/PublicQrCodeShare'; import { encryptObject, getSession } from '../../../Services/Others'; import { PublicQrCodepost } from '../../../Features/ConfigMasterPage/ConfigMasterPage'; import Buttons from '../../../Components/Forms/Buttons'; import { changeBreadCrumb } from '../../../Features/AppPage/CenterPage'; import { Modal } from 'antd'; import { jsPDF } from 'jspdf'; import { FaFacebookF, FaWhatsapp, FaTwitter, FaLinkedinIn, FaEnvelope, } from 'react-icons/fa'; import QRCodeLib from 'qrcode'; import { LuDownload } from 'react-icons/lu'; import { BsFileEarmarkPdf } from 'react-icons/bs'; const subDirectory = import.meta.env.ENV_MAIN_BASE_URL || '/'; const MenuQRCode = () => { const dispatch = useDispatch(); // Session const CompId = getSession('CompId'); const BranchId = getSession('BranchId'); const AppId = getSession('AppId'); const UserId = getSession('UserId'); // States const [qrCodeUrl, setQrCodeUrl] = useState(''); const [qrCodeDataUrl, setQrCodeDataUrl] = useState(''); const [messageType, setMessageType] = useState(null); const [messageData, setMessageData] = useState(null); const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false); const [pdfPreviewUrl, setPdfPreviewUrl] = useState(''); const [socialIconsDataUrls, setSocialIconsDataUrls] = useState([]); const cardRef = useRef(null); const socialIconsRef = useRef(null); // breadcrumb useEffect(() => { const items = [ { name: 'Home', link: `${subDirectory}app-page/home`, }, ]; dispatch(changeBreadCrumb({ items })); HandleSubmit(); }, [dispatch]); // Generate QR Code as Data URL using qrcode library useEffect(() => { if (qrCodeUrl) { QRCodeLib.toDataURL(qrCodeUrl, { width: 200, margin: 1, color: { dark: '#000000', light: '#FFFFFF', }, }) .then((url) => { setQrCodeDataUrl(url); }) .catch((err) => { console.error('QR generation error:', err); }); } }, [qrCodeUrl]); // Convert social icons to images useEffect(() => { if (qrCodeUrl && socialIconsRef.current) { const convertIconsToImages = async () => { try { const icons = socialIconsRef.current.querySelectorAll( '.social-icon-container' ); const dataUrls = []; for (let icon of icons) { const svg = icon.querySelector('svg'); if (svg) { const svgData = new XMLSerializer().serializeToString(svg); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const img = new Image(); canvas.width = 16; canvas.height = 16; await new Promise((resolve) => { img.onload = () => { ctx.fillStyle = '#0f1724'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.globalCompositeOperation = 'destination-in'; ctx.drawImage(img, 0, 0, 16, 16); const dataUrl = canvas.toDataURL('image/png'); dataUrls.push(dataUrl); resolve(); }; img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData))); }); } } setSocialIconsDataUrls(dataUrls); } catch (err) { console.error('Icon conversion error:', err); } }; setTimeout(convertIconsToImages, 100); } }, [qrCodeUrl]); const HandleSubmit = async () => { try { let data = { BranchId, CompId, AppId, UserId }; const encrypted = encryptObject(data); const postData = { Url: encrypted, CreatedBy: UserId }; const res = await dispatch(PublicQrCodepost(postData)).unwrap(); if (res?.data?.statusCode === 1) { const QrUrl = `${subDirectory}MenuQRCode?code=${res?.data?.ReferenceNo}`; setQrCodeUrl(QrUrl); setMessageType('success'); setMessageData('QR Code generated.'); } else { setMessageType('error'); setMessageData(res?.data?.message || 'Failed to generate QR.'); } } catch (error) { console.error('HandleSubmit Error:', error); setMessageType('error'); setMessageData('An unexpected error occurred.'); } }; const onComplete = useCallback(() => { setMessageData(null); setMessageType(null); }, []); // const clearData = () => { // setQrCodeUrl(""); // setQrCodeDataUrl(""); // setTableId(null); // if (pdfPreviewUrl) { // URL.revokeObjectURL(pdfPreviewUrl); // setPdfPreviewUrl(""); // } // }; const generatePdfFromCard = async (openPreview = true) => { try { if (!qrCodeDataUrl || socialIconsDataUrls.length < 4) { setMessageType('error'); setMessageData('QR Code and icons not ready. Please wait a moment.'); return; } const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4', }); const pageWidth = pdf.internal.pageSize.getWidth(); const pageHeight = pdf.internal.pageSize.getHeight(); // Card dimensions const cardWidth = 350; const cardX = (pageWidth - cardWidth) / 2; let yPos = 80; // Background card pdf.setFillColor(255, 255, 255); pdf.roundedRect(cardX, yPos, cardWidth, 500, 8, 8, 'F'); // Shadow effect pdf.setDrawColor(0, 0, 0); pdf.setLineWidth(0.5); pdf.setGState(pdf.GState({ opacity: 0.1 })); pdf.roundedRect(cardX, yPos, cardWidth, 500, 8, 8, 'S'); pdf.setGState(pdf.GState({ opacity: 1 })); yPos += 40; // Title pdf.setFontSize(16); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(15, 23, 36); pdf.text('Scan the QR Code', pageWidth / 2, yPos, { align: 'center' }); yPos += 40; // QR Code background frame const qrSize = 200; const qrX = (pageWidth - qrSize) / 2; // Outer decorative frame pdf.setFillColor(255, 255, 255); pdf.roundedRect( qrX - 20, yPos - 20, qrSize + 40, qrSize + 40, 12, 12, 'F' ); // Shadow for QR frame pdf.setDrawColor(0, 0, 0); pdf.setGState(pdf.GState({ opacity: 0.06 })); pdf.roundedRect( qrX - 20, yPos - 20, qrSize + 40, qrSize + 40, 12, 12, 'S' ); pdf.setGState(pdf.GState({ opacity: 1 })); // Inner white background for QR pdf.setFillColor(255, 255, 255); pdf.roundedRect(qrX - 8, yPos - 8, qrSize + 16, qrSize + 16, 8, 8, 'F'); // Add QR Code image pdf.addImage(qrCodeDataUrl, 'PNG', qrX, yPos, qrSize, qrSize); yPos += qrSize + 40; // MENU button const buttonWidth = 120; const buttonHeight = 45; const buttonX = (pageWidth - buttonWidth) / 2; pdf.setFillColor(15, 107, 117); pdf.roundedRect(buttonX, yPos, buttonWidth, buttonHeight, 8, 8, 'F'); pdf.setFontSize(22); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(255, 255, 255); pdf.text('MENU', pageWidth / 2, yPos + 30, { align: 'center' }); yPos += buttonHeight + 30; // Social icons with actual images const iconSize = 36; const iconSpacing = 18; const totalIconsWidth = iconSize * 4 + iconSpacing * 3; let iconX = (pageWidth - totalIconsWidth) / 2; pdf.setFillColor(255, 255, 255); pdf.setDrawColor(230, 238, 240); pdf.setLineWidth(1); socialIconsDataUrls.forEach((iconDataUrl) => { // Draw circle background pdf.circle(iconX + iconSize / 2, yPos, iconSize / 2, 'FD'); // Draw icon image centered in circle const iconImageSize = 16; const iconImageX = iconX + (iconSize - iconImageSize) / 2; const iconImageY = yPos - iconImageSize / 2; pdf.addImage( iconDataUrl, 'PNG', iconImageX, iconImageY, iconImageSize, iconImageSize ); iconX += iconSize + iconSpacing; }); yPos += 50; // URL text at bottom pdf.setFontSize(10); pdf.setTextColor(156, 163, 175); const urlText = qrCodeUrl.length > 50 ? qrCodeUrl.substring(0, 47) + '...' : qrCodeUrl; pdf.text(urlText, pageWidth / 2, yPos, { align: 'center' }); // Create blob for preview const pdfBlob = pdf.output('blob'); const blobUrl = URL.createObjectURL(pdfBlob); if (pdfPreviewUrl) { URL.revokeObjectURL(pdfPreviewUrl); } setPdfPreviewUrl(blobUrl); if (openPreview) { setIsPreviewModalOpen(true); } else { pdf.save('menu-qr.pdf'); } } catch (err) { console.error('PDF generation failed', err); setMessageType('error'); setMessageData('Failed to generate PDF.'); } }; const downloadPreviewPdf = () => { if (!pdfPreviewUrl) return; fetch(pdfPreviewUrl) .then((r) => r.blob()) .then((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'menu-qr.pdf'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); }); }; return (
{qrCodeUrl}