'use client'; import { useRef, useState } from 'react'; import { posApi } from '@/lib/api-client'; import { formatPrice } from '@/lib/money'; import type { PosReceipt } from '@/types/checkout'; interface ReceiptModalProps { receipt: PosReceipt; initialEmail?: string; onDelivered: () => void; onReturn?: (orderId: string, receipt: PosReceipt) => void; showActions?: boolean; // false when used just for printing } export default function ReceiptModal({ receipt, initialEmail = '', onDelivered, onReturn, showActions = true, }: ReceiptModalProps) { const articleRef = useRef(null); const [email, setEmail] = useState(initialEmail); const [sending, setSending] = useState(false); const [error, setError] = useState(''); const printReceipt = () => { // Hide everything except the ticket content before printing document.querySelectorAll('.no-print').forEach((el) => { (el as HTMLElement).style.visibility = 'hidden'; }); window.print(); // Restore after printing document.querySelectorAll('.no-print').forEach((el) => { (el as HTMLElement).style.visibility = ''; }); onDelivered(); }; const emailReceipt = async (event: React.FormEvent) => { event.preventDefault(); setSending(true); setError(''); try { await posApi.emailReceipt(receipt.orderId, email.trim()); onDelivered(); } catch (err) { setError(err instanceof Error ? err.message : 'No se pudo enviar el ticket'); } finally { setSending(false); } }; return (
{/* Ticket content - only this gets printed */}
{/* Timestamp */}
Ticket #{receipt.receiptNumber} {new Date(receipt.issuedAt).toLocaleString('es-ES', { dateStyle: 'short', timeStyle: 'short' })}
{/* Logo */}
Logo
{receipt.header &&

{receipt.header}

}

{receipt.company.name}

{receipt.company.address &&

{receipt.company.address}

} {receipt.company.taxId &&

NIF/CIF: {receipt.company.taxId}

} {(receipt.company.phone || receipt.company.email) && (

{[receipt.company.phone, receipt.company.email].filter(Boolean).join(' · ')}

)}

Ticket: {receipt.receiptNumber}

Fecha: {new Date(receipt.issuedAt).toLocaleString('es-ES')}

Terminal: {receipt.terminal.name}

Cajero: {receipt.cashier?.split('@')[0] ?? '—'}

{receipt.items.map((item, index) => ( ))}
Artículo Cant. Subtotal
{item.name} {formatPrice(item.unitPriceCents)}/ud{item.freeItem ? ' · libre' : ''} {item.discountCents > 0 && ( Dto. −{formatPrice(item.discountCents)} )} {item.quantity} {formatPrice(item.totalCents)}

Subtotal {formatPrice(receipt.subtotalCents)}

{receipt.discountCents > 0 && (

Descuentos −{formatPrice(receipt.discountCents)}

)}

IVA {formatPrice(receipt.taxCents)}

Total {formatPrice(receipt.totalCents)}

Formas de pago

{receipt.payments.map((payment, index) => (
{payment.methodLabel} {formatPrice(payment.amountCents)} {payment.tenderedCents !== null && ( Entregado {formatPrice(payment.tenderedCents)} )} {payment.changeCents > 0 && ( Cambio {formatPrice(payment.changeCents)} )}
))} {receipt.changeCents > 0 && (

Total a devolver {formatPrice(receipt.changeCents)}

)}

{receipt.returnPolicy}

{receipt.footer &&

{receipt.footer}

}
{/* Actions - hidden when printing */} {showActions && (

Imprime o envía el ticket para preparar la siguiente venta.

{onReturn && !receipt.isReturn && ( )}
setEmail(event.target.value)} placeholder="cliente@email.es" className="no-print min-h-14 min-w-0 flex-1 rounded-xl border-2 border-gray-200 px-4 outline-none focus:border-[#2D6A4F]" />
{error && (

{error}

)}
)}
{/* Print-only styles */}
); }