"use client"; import { useEffect, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useTranslations } from "next-intl"; import { Server, Wifi, WifiOff, Trash2, Plus, Loader2 } from "lucide-react"; import { apiGet, apiPatch } from "@/lib/api/client"; import { listPrintAgents, createPairingCode, revokePrintAgent, testPrintDevice, deviceOptions, type PairingCode, } from "@/lib/api/print-agents"; import { printErrorMessage } from "@/lib/api/print"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { LabeledField } from "@/components/ui/labeled-field"; import { useConfirm } from "@/components/providers/confirm-provider"; import { notify } from "@/lib/notify"; type BranchPrintSettings = { branchId: string; receiptPrinterIp?: string | null; receiptPrinterPort?: number | null; kitchenPrinterIp?: string | null; kitchenPrinterPort?: number | null; paperWidthMm: number; autoCutEnabled: boolean; receiptHeader?: string | null; receiptFooter?: string | null; wifiPassword?: string | null; posDeviceIp?: string | null; posDevicePort?: number | null; receiptPrintDeviceId?: string | null; kitchenPrintDeviceId?: string | null; }; type SettingsPrinterPanelProps = { cafeId: string; onOpenPrintTest?: () => void; }; export function SettingsPrinterPanel({ cafeId, onOpenPrintTest }: SettingsPrinterPanelProps) { const t = useTranslations("print"); const tSettings = useTranslations("settings"); const tCommon = useTranslations("common"); const [message, setMessage] = useState(null); const [receiptIp, setReceiptIp] = useState(""); const [receiptPort, setReceiptPort] = useState("9100"); const [kitchenIp, setKitchenIp] = useState(""); const [kitchenPort, setKitchenPort] = useState("9100"); const [paperWidth, setPaperWidth] = useState("80"); const [autoCut, setAutoCut] = useState(true); const [receiptHeader, setReceiptHeader] = useState(""); const [receiptFooter, setReceiptFooter] = useState(""); const [wifiPassword, setWifiPassword] = useState(""); const [posDeviceIp, setPosDeviceIp] = useState(""); const [posDevicePort, setPosDevicePort] = useState("8088"); const [receiptDeviceId, setReceiptDeviceId] = useState(""); const [kitchenDeviceId, setKitchenDeviceId] = useState(""); const { data: agents = [] } = useQuery({ queryKey: ["print-agents", cafeId], queryFn: () => listPrintAgents(cafeId), enabled: !!cafeId, }); const devices = deviceOptions(agents); const { data: branches = [], isLoading: branchesLoading } = useQuery({ queryKey: ["branches", cafeId], queryFn: () => apiGet<{ id: string }[]>(`/api/cafes/${cafeId}/branches`), enabled: !!cafeId, }); const branchId = branches[0]?.id; const { data: settings, refetch } = useQuery({ queryKey: ["branch-print-settings", cafeId, branchId], queryFn: () => apiGet( `/api/cafes/${cafeId}/branches/${branchId}/print-settings` ), enabled: !!cafeId && !!branchId, }); useEffect(() => { if (!settings) return; setReceiptIp(settings.receiptPrinterIp ?? ""); setReceiptPort(String(settings.receiptPrinterPort ?? 9100)); setKitchenIp(settings.kitchenPrinterIp ?? ""); setKitchenPort(String(settings.kitchenPrinterPort ?? 9100)); setPaperWidth(String(settings.paperWidthMm === 58 ? 58 : 80)); setAutoCut(settings.autoCutEnabled); setReceiptHeader(settings.receiptHeader ?? ""); setReceiptFooter(settings.receiptFooter ?? ""); setWifiPassword(settings.wifiPassword ?? ""); setPosDeviceIp(settings.posDeviceIp ?? ""); setPosDevicePort(String(settings.posDevicePort ?? 8088)); setReceiptDeviceId(settings.receiptPrintDeviceId ?? ""); setKitchenDeviceId(settings.kitchenPrintDeviceId ?? ""); }, [settings]); const save = useMutation({ mutationFn: () => apiPatch( `/api/cafes/${cafeId}/branches/${branchId}/print-settings`, { receiptPrinterIp: receiptIp.trim() || null, receiptPrinterPort: parseInt(receiptPort, 10) || 9100, kitchenPrinterIp: kitchenIp.trim() || null, kitchenPrinterPort: parseInt(kitchenPort, 10) || 9100, paperWidthMm: paperWidth === "58" ? 58 : 80, autoCutEnabled: autoCut, receiptHeader: receiptHeader.trim() || null, receiptFooter: receiptFooter.trim() || null, wifiPassword: wifiPassword.trim() || null, posDeviceIp: posDeviceIp.trim() || null, posDevicePort: parseInt(posDevicePort, 10) || 8088, receiptPrintDeviceId: receiptDeviceId || null, kitchenPrintDeviceId: kitchenDeviceId || null, } ), onSuccess: () => { setMessage(t("settingsSaved")); void refetch(); }, }); const qc = useQueryClient(); const confirm = useConfirm(); const [pairing, setPairing] = useState(null); const createCode = useMutation({ mutationFn: () => createPairingCode(cafeId), onSuccess: (c) => { setPairing(c); void qc.invalidateQueries({ queryKey: ["print-agents", cafeId] }); }, onError: () => notify.error(t("agents.codeError")), }); const revoke = useMutation({ mutationFn: (id: string) => revokePrintAgent(cafeId, id), onSuccess: () => qc.invalidateQueries({ queryKey: ["print-agents", cafeId] }), }); const testDevice = useMutation({ mutationFn: (deviceId: string) => testPrintDevice(cafeId, deviceId), onSuccess: () => notify.success(t("testSent")), onError: (err) => notify.error(printErrorMessage(err, t)), }); const handleRevoke = async (id: string, name: string) => { const ok = await confirm({ description: t("agents.revokeConfirm", { name }), variant: "destructive", confirmLabel: tCommon("confirm"), }); if (ok) revoke.mutate(id); }; if (branchesLoading) { return

{tCommon("loading")}

; } if (!branchId) { return (

{t("noBranchForPrinter")}

); } return ( {t("printerSettings")} {onOpenPrintTest ? ( ) : null} {message ? (

{message}

) : null} {/* Print servers — auto-discovered printers via the local agent */}

{t("agents.title")}

{t("agents.hint")}

{pairing ? (

{t("agents.pairingTitle")}

{pairing.code}

{t("agents.pairingSteps")}

) : null} {agents.length === 0 ? (

{t("agents.empty")}

) : (
    {agents.map((a) => (
  • {a.online ? ( ) : ( )} {a.name} {a.online ? t("agents.online") : t("agents.offline")}
    {a.devices.length > 0 ? (
      {a.devices.map((d) => (
    • {d.displayName} ({d.kind})
    • ))}
    ) : a.online ? (

    {t("agents.noDevices")}

    ) : null}
  • ))}
)} {devices.length > 0 ? (
) : null}
setReceiptIp(e.target.value)} placeholder="192.168.1.100" dir="ltr" className="text-end" /> setReceiptPort(e.target.value)} dir="ltr" className="text-end" /> setKitchenIp(e.target.value)} placeholder="192.168.1.101" dir="ltr" className="text-end" /> setKitchenPort(e.target.value)} dir="ltr" className="text-end" />
setReceiptHeader(e.target.value)} /> setReceiptFooter(e.target.value)} /> setWifiPassword(e.target.value)} dir="ltr" className="text-end" />

{t("posDeviceSection")}

{t("posDeviceHint")}

setPosDeviceIp(e.target.value)} placeholder="192.168.1.50" dir="ltr" className="text-end" /> setPosDevicePort(e.target.value)} dir="ltr" className="text-end" />
); }