'use client'; import { useRef, useState, useEffect } from 'react'; import type { Cfdi } from '@horux/shared'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { CfdiInvoice } from './cfdi-invoice'; import { getCfdiXml } from '@/lib/api/cfdi'; import { Download, FileText, Loader2, Printer } from 'lucide-react'; interface CfdiConcepto { descripcion: string; cantidad: number; valorUnitario: number; importe: number; } interface CfdiViewerModalProps { cfdi: Cfdi | null; open: boolean; onClose: () => void; } function parseConceptosFromXml(xmlString: string): CfdiConcepto[] { try { const parser = new DOMParser(); const doc = parser.parseFromString(xmlString, 'text/xml'); const conceptos: CfdiConcepto[] = []; // Find all Concepto elements const elements = doc.getElementsByTagName('*'); for (let i = 0; i < elements.length; i++) { if (elements[i].localName === 'Concepto') { const el = elements[i]; conceptos.push({ descripcion: el.getAttribute('Descripcion') || '', cantidad: parseFloat(el.getAttribute('Cantidad') || '1'), valorUnitario: parseFloat(el.getAttribute('ValorUnitario') || '0'), importe: parseFloat(el.getAttribute('Importe') || '0'), }); } } return conceptos; } catch { return []; } } export function CfdiViewerModal({ cfdi, open, onClose }: CfdiViewerModalProps) { const invoiceRef = useRef(null); const [conceptos, setConceptos] = useState([]); const [downloading, setDownloading] = useState<'pdf' | 'xml' | null>(null); const [xmlContent, setXmlContent] = useState(null); useEffect(() => { if (cfdi?.xmlOriginal) { setXmlContent(cfdi.xmlOriginal); setConceptos(parseConceptosFromXml(cfdi.xmlOriginal)); } else { setXmlContent(null); setConceptos([]); } }, [cfdi]); const handleDownloadPdf = async () => { if (!invoiceRef.current || !cfdi) return; setDownloading('pdf'); try { const html2pdf = (await import('html2pdf.js')).default; const opt = { margin: 10, filename: `factura-${cfdi.uuidFiscal.substring(0, 8)}.pdf`, image: { type: 'jpeg' as const, quality: 0.98 }, html2canvas: { scale: 2, useCORS: true }, jsPDF: { unit: 'mm' as const, format: 'a4' as const, orientation: 'portrait' as const }, }; await html2pdf().set(opt).from(invoiceRef.current).save(); } catch (error) { console.error('Error generating PDF:', error); alert('Error al generar el PDF'); } finally { setDownloading(null); } }; const handleDownloadXml = async () => { if (!cfdi) return; setDownloading('xml'); try { let xml = xmlContent; if (!xml) { xml = await getCfdiXml(cfdi.id); } if (!xml) { alert('No hay XML disponible para este CFDI'); return; } const blob = new Blob([xml], { type: 'application/xml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `cfdi-${cfdi.uuidFiscal.substring(0, 8)}.xml`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } catch (error) { console.error('Error downloading XML:', error); alert('Error al descargar el XML'); } finally { setDownloading(null); } }; const handlePrint = () => { if (!invoiceRef.current) return; // Create a print-specific stylesheet const printStyles = document.createElement('style'); printStyles.innerHTML = ` @media print { body * { visibility: hidden; } #cfdi-print-area, #cfdi-print-area * { visibility: visible; } #cfdi-print-area { position: absolute; left: 0; top: 0; width: 100%; padding: 20px; } @page { size: A4; margin: 15mm; } } `; document.head.appendChild(printStyles); // Add ID to the invoice container for print targeting invoiceRef.current.id = 'cfdi-print-area'; // Trigger print window.print(); // Clean up document.head.removeChild(printStyles); invoiceRef.current.removeAttribute('id'); }; if (!cfdi) return null; return ( !isOpen && onClose()}>
Vista de Factura
); }