import html2canvas from 'html2canvas'; import jsPDF from 'jspdf'; /** * Export invoice element as high-quality image */ export async function exportInvoiceAsImage( element: HTMLElement, options?: { scale?: number; format?: 'png' | 'jpeg'; quality?: number } ): Promise { const { scale = 3, format = 'png', quality = 0.95 } = options || {}; const canvas = await html2canvas(element, { scale, // Higher quality for better readability useCORS: true, backgroundColor: '#ffffff', logging: false, windowWidth: element.scrollWidth, windowHeight: element.scrollHeight, }); const imageFormat = format === 'jpeg' ? 'image/jpeg' : 'image/png'; return canvas.toDataURL(imageFormat, quality); } /** * Downloads the invoice as an image file * @param base64Image - Base64 encoded image string * @param filename - Name of the file to download */ export function downloadInvoiceImage(base64Image: string, filename: string = 'invoice.png') { const link = document.createElement('a'); link.href = base64Image; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); } /** * Shares invoice via WhatsApp Web * @param phoneNumber - Customer's phone number (with country code, e.g., 919876543210) * @param billNumber - Invoice/Bill number * @param amount - Total amount * @param base64Image - Base64 encoded image (optional, for future file sharing) */ export function shareInvoiceViaWhatsApp( phoneNumber: string, billNumber: string, amount: number, language: 'en' | 'mr' = 'mr' ) { // Clean phone number (remove spaces, hyphens, etc.) const cleanedNumber = phoneNumber.replace(/[^\d+]/g, ''); // Ensure country code is present const formattedNumber = cleanedNumber.startsWith('+') || cleanedNumber.startsWith('91') ? cleanedNumber : `91${cleanedNumber}`; // Create message text based on language const message = language === 'mr' ? `नमस्कार,\n\nतुमचे बिल नंबर *${billNumber}* तयार झाले आहे.\n\nएकूण रक्कम: ₹${amount.toLocaleString('en-IN')}\n\nकृपया रक्कम वेळेवर भरावी.\n\nधन्यवाद!` : `Hello,\n\nYour bill number *${billNumber}* is ready.\n\nTotal Amount: ₹${amount.toLocaleString('en-IN')}\n\nPlease pay on time.\n\nThank you!`; // WhatsApp Web/API URL const whatsappUrl = `https://wa.me/${formattedNumber}?text=${encodeURIComponent(message)}`; // Open WhatsApp window.open(whatsappUrl, '_blank'); } /** * Shares invoice image via WhatsApp using the device's native share (mobile) * @param base64Image - Base64 encoded image * @param billNumber - Invoice number * @param partyName - Customer name */ export async function shareInvoiceImageNative( base64Image: string, billNumber: string, partyName: string ) { try { // Convert base64 to blob const response = await fetch(base64Image); const blob = await response.blob(); // Create a file from blob const file = new File([blob], `Invoice_${billNumber}.png`, { type: 'image/png' }); // Check if Web Share API is supported if (navigator.share && navigator.canShare({ files: [file] })) { await navigator.share({ title: `Invoice ${billNumber}`, text: `Invoice for ${partyName}`, files: [file], }); return true; } else { // Fallback: Download the image downloadInvoiceImage(base64Image, `Invoice_${billNumber}_${partyName}.png`); return false; } } catch (error) { console.error('Error sharing invoice:', error); // Fallback: Download the image downloadInvoiceImage(base64Image, `Invoice_${billNumber}_${partyName}.png`); return false; } } /** * Formats phone number for WhatsApp * @param phone - Phone number in any format * @returns Formatted phone number with country code */ export function formatPhoneForWhatsApp(phone: string): string { const cleaned = phone.replace(/[^\d+]/g, ''); if (cleaned.startsWith('+91')) { return cleaned; } else if (cleaned.startsWith('91') && cleaned.length === 12) { return `+${cleaned}`; } else if (cleaned.length === 10) { return `+91${cleaned}`; } return cleaned; } /** * Validates Indian phone number * @param phone - Phone number to validate * @returns true if valid */ export function isValidIndianPhoneNumber(phone: string): boolean { const cleaned = phone.replace(/[^\d]/g, ''); // Check if it's a 10-digit number starting with 6-9 if (cleaned.length === 10 && /^[6-9]\d{9}$/.test(cleaned)) { return true; } // Check if it's a 12-digit number starting with 91 if (cleaned.length === 12 && cleaned.startsWith('91') && /^91[6-9]\d{9}$/.test(cleaned)) { return true; } return false; } /** * Export invoice as PDF */ export async function exportInvoiceAsPDF( element: HTMLElement, filename: string = 'invoice.pdf', options?: { orientation?: 'portrait' | 'landscape'; format?: 'a4' | 'letter' } ): Promise { const { orientation = 'portrait', format = 'a4' } = options || {}; // Generate high-quality image first const imageData = await exportInvoiceAsImage(element, { scale: 3, format: 'jpeg', quality: 0.95 }); // Create PDF const pdf = new jsPDF({ orientation, unit: 'mm', format, }); // Calculate dimensions to fit page const imgProps = pdf.getImageProperties(imageData); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; // Add image to PDF pdf.addImage(imageData, 'JPEG', 0, 0, pdfWidth, pdfHeight); // Save PDF pdf.save(filename); } /** * Generate invoice text for WhatsApp or SMS */ export function generateInvoiceText( billNumber: string, partyName: string, items: Array<{ name: string; quantity: number; rate: number; amount: number }>, charges: { bardhana?: number; hamali?: number; adhath?: number; cess?: number; gaadiBharni?: number }, total: number, language: 'en' | 'mr' = 'mr' ): string { if (language === 'mr') { let text = `🧾 *बिल नंबर:* ${billNumber}\n`; text += `👤 *पार्टी:* ${partyName}\n`; text += `📅 *तारीख:* ${new Date().toLocaleDateString('mr-IN')}\n\n`; text += `*📦 माल तपशील:*\n`; text += `${'─'.repeat(35)}\n`; items.forEach((item, i) => { text += `${i + 1}. ${item.name}\n`; text += ` ${item.quantity} पोत्या × ₹${item.rate} = ₹${item.amount.toLocaleString('en-IN')}\n`; }); text += `${'─'.repeat(35)}\n`; // Add charges if any const totalCharges = (charges.bardhana || 0) + (charges.hamali || 0) + (charges.adhath || 0) + (charges.cess || 0) + (charges.gaadiBharni || 0); if (totalCharges > 0) { text += `\n*💰 खर्च:*\n`; if (charges.bardhana) text += ` बर्धाना: ₹${charges.bardhana.toLocaleString('en-IN')}\n`; if (charges.hamali) text += ` हमाली: ₹${charges.hamali.toLocaleString('en-IN')}\n`; if (charges.adhath) text += ` अडत: ₹${charges.adhath.toLocaleString('en-IN')}\n`; if (charges.cess) text += ` सेस: ₹${charges.cess.toLocaleString('en-IN')}\n`; if (charges.gaadiBharni) text += ` गाडी भरणी: ₹${charges.gaadiBharni.toLocaleString('en-IN')}\n`; text += `${'─'.repeat(35)}\n`; } text += `\n*💵 एकूण रक्कम: ₹${total.toLocaleString('en-IN')}*\n\n`; text += `कृपया रक्कम वेळेवर भरावी.\n\n`; text += `धन्यवाद! 🙏`; return text; } else { let text = `🧾 *Bill No:* ${billNumber}\n`; text += `👤 *Party:* ${partyName}\n`; text += `📅 *Date:* ${new Date().toLocaleDateString('en-IN')}\n\n`; text += `*📦 Items:*\n`; text += `${'─'.repeat(35)}\n`; items.forEach((item, i) => { text += `${i + 1}. ${item.name}\n`; text += ` ${item.quantity} bags × ₹${item.rate} = ₹${item.amount.toLocaleString('en-IN')}\n`; }); text += `${'─'.repeat(35)}\n`; const totalCharges = (charges.bardhana || 0) + (charges.hamali || 0) + (charges.adhath || 0) + (charges.cess || 0) + (charges.gaadiBharni || 0); if (totalCharges > 0) { text += `\n*💰 Charges:*\n`; if (charges.bardhana) text += ` Bardhana: ₹${charges.bardhana.toLocaleString('en-IN')}\n`; if (charges.hamali) text += ` Hamali: ₹${charges.hamali.toLocaleString('en-IN')}\n`; if (charges.adhath) text += ` Commission: ₹${charges.adhath.toLocaleString('en-IN')}\n`; if (charges.cess) text += ` Cess: ₹${charges.cess.toLocaleString('en-IN')}\n`; if (charges.gaadiBharni) text += ` Loading: ₹${charges.gaadiBharni.toLocaleString('en-IN')}\n`; text += `${'─'.repeat(35)}\n`; } text += `\n*💵 Total Amount: ₹${total.toLocaleString('en-IN')}*\n\n`; text += `Please pay on time.\n\n`; text += `Thank you! 🙏`; return text; } } /** * Share detailed invoice text via WhatsApp */ export function shareDetailedInvoiceText( phoneNumber: string, invoiceText: string ): void { const formattedPhone = formatPhoneForWhatsApp(phoneNumber); const encodedText = encodeURIComponent(invoiceText); const whatsappUrl = `https://wa.me/${formattedPhone}?text=${encodedText}`; window.open(whatsappUrl, '_blank'); } /** * Prints the invoice * @param element - The invoice element to print */ export function printInvoice(element?: HTMLElement) { if (element) { // Create a new window with just the invoice content const printWindow = window.open('', '_blank'); if (printWindow) { printWindow.document.write(` Print Invoice ${element.innerHTML} `); printWindow.document.close(); setTimeout(() => { printWindow.print(); printWindow.close(); }, 250); } } else { // Default browser print window.print(); } }