"use client"; import { useTranslations, useLocale } from "next-intl"; import { Printer } from "lucide-react"; import type { Order } from "@/lib/api/types"; import { formatCurrency } from "@/lib/format"; import { formatOrderNumber } from "@/lib/order-number"; import { buildThermalDocument, printThermal } from "@/lib/thermal-print"; import { resolveMediaUrl } from "@/lib/api/client"; import { Button } from "@/components/ui/button"; import "./pos-receipt-print.css"; export type KitchenSlipLine = { name: string; quantity: number; notes?: string; }; type PosSlipModalProps = { variant: "kitchen" | "bill"; cafeName: string; /** Café logo for receipt branding. */ logoUrl?: string; /** Address / phone line shown under the café name on the bill. */ tagline?: string; /** Custom header note from branch print settings (bill only). */ receiptHeader?: string | null; /** Custom footer note from branch print settings (bill only). */ receiptFooter?: string | null; /** WiFi password printed near the bill footer. */ wifiPassword?: string | null; /** Paper width in mm — 58 or 80 (default 80). */ paperWidthMm?: number; onClose: () => void; /** Full order for customer bill */ order?: Order; /** Kitchen ticket lines (new items or full order) */ kitchenLines?: KitchenSlipLine[]; tableNumber?: string | number | null; orderId?: string; guestName?: string | null; createdAt?: string; }; export function PosSlipModal({ variant, cafeName, logoUrl, tagline, receiptHeader, receiptFooter, wifiPassword, paperWidthMm, onClose, order, kitchenLines = [], tableNumber, orderId, guestName, createdAt, }: PosSlipModalProps) { const t = useTranslations("receipt"); const locale = useLocale(); const numberLocale = locale === "en" ? "en-US" : "fa-IR"; const dateSource = order?.createdAt ?? createdAt ?? new Date().toISOString(); const formattedDate = new Intl.DateTimeFormat( locale === "en" ? "en-US" : "fa-IR", { dateStyle: "short", timeStyle: "short" } ).format(new Date(dateSource)); const table = order?.tableNumber ?? tableNumber ?? "—"; const orderNo = order ? formatOrderNumber(order) : orderId ? formatOrderNumber({ id: orderId }) : null; const guest = order?.guestName ?? guestName; const activeBillItems = order?.items.filter((i) => !i.isVoided) ?? []; const paymentKey = (method: string) => { const m = method.toLowerCase(); if (m === "cash") return t("payment.cash"); if (m === "card") return t("payment.card"); if (m === "credit") return t("payment.credit"); return method; }; // ── Build meta row ───────────────────────────────────────────────────────── const metaParts: string[] = []; metaParts.push(`${t("table")}: ${table}`); if (orderNo) metaParts.push(`${t("order")}: #${orderNo}`); if (guest) metaParts.push(`${t("guest")}: ${guest}`); const metaRow = metaParts.join(" | "); // ── Print handler ───────────────────────────────────────────────────────── const handlePrint = () => { const slipData = variant === "kitchen" ? { cafeName, title: t("kitchenTitle"), date: formattedDate, metaRow, lines: kitchenLines.map((l) => ({ name: l.name, quantity: l.quantity, notes: l.notes, })), footer: t("kitchenFooter"), locale, } : { cafeName, logoUrl: resolveMediaUrl(logoUrl), tagline, header: receiptHeader?.trim() || undefined, wifi: wifiPassword?.trim() || undefined, paperWidthMm, title: t("billTitle"), date: formattedDate, metaRow, lines: activeBillItems.map((item) => ({ name: item.menuItemName, quantity: item.quantity, price: formatCurrency(item.unitPrice * item.quantity, numberLocale), })), totals: { total: formatCurrency(order!.total, numberLocale), payments: order!.payments?.map((p) => ({ method: paymentKey(p.method), amount: formatCurrency(p.amount, numberLocale), })), }, footer: receiptFooter?.trim() || t("thankYou"), locale, }; printThermal(buildThermalDocument(slipData)); }; // ── Render ───────────────────────────────────────────────────────────────── return (