"use client"; import { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { formatCurrency, cn } from "@/lib/utils"; interface CashRegister { id: string; openingAmount: number; closedAt: string | null; openedAt: string; site: { id: string; name: string; }; user: { id: string; firstName: string; lastName: string; }; _count: { sales: number; payments: number; }; paymentBreakdown?: Record; totalCashSales?: number; expectedAmount?: number; } interface CashRegisterStatusProps { siteId: string; onRegisterStatusChange: (isOpen: boolean, registerId?: string) => void; } export function CashRegisterStatus({ siteId, onRegisterStatusChange, }: CashRegisterStatusProps) { const [register, setRegister] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showOpenDialog, setShowOpenDialog] = useState(false); const [showCloseDialog, setShowCloseDialog] = useState(false); const [openingAmount, setOpeningAmount] = useState("0"); const [closingAmount, setClosingAmount] = useState(""); const [closingNotes, setClosingNotes] = useState(""); const [actionLoading, setActionLoading] = useState(false); // Fetch current register status const fetchRegisterStatus = useCallback(async () => { setLoading(true); setError(null); try { const response = await fetch( `/api/cash-register?siteId=${siteId}&status=open` ); if (!response.ok) { throw new Error("Error al verificar estado de caja"); } const data = await response.json(); setRegister(data); onRegisterStatusChange(!!data, data?.id); } catch (err) { setError(err instanceof Error ? err.message : "Error desconocido"); onRegisterStatusChange(false); } finally { setLoading(false); } }, [siteId, onRegisterStatusChange]); useEffect(() => { fetchRegisterStatus(); }, [fetchRegisterStatus]); const handleOpenRegister = async () => { setActionLoading(true); setError(null); try { const response = await fetch("/api/cash-register", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ siteId, openingAmount: parseFloat(openingAmount) || 0, }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Error al abrir caja"); } setShowOpenDialog(false); setOpeningAmount("0"); await fetchRegisterStatus(); } catch (err) { setError(err instanceof Error ? err.message : "Error desconocido"); } finally { setActionLoading(false); } }; const handleCloseRegister = async () => { if (!register) return; setActionLoading(true); setError(null); try { const response = await fetch(`/api/cash-register/${register.id}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ closingAmount: parseFloat(closingAmount) || 0, notes: closingNotes || undefined, }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Error al cerrar caja"); } setShowCloseDialog(false); setClosingAmount(""); setClosingNotes(""); await fetchRegisterStatus(); } catch (err) { setError(err instanceof Error ? err.message : "Error desconocido"); } finally { setActionLoading(false); } }; // Loading state if (loading) { return (
Verificando estado de caja...
); } // Open Register Dialog if (showOpenDialog) { return (

Abrir Caja

setOpeningAmount(e.target.value)} min={0} step={0.01} disabled={actionLoading} />
{error && (
{error}
)}
); } // Close Register Dialog if (showCloseDialog && register) { const expectedAmount = register.expectedAmount || 0; const closingValue = parseFloat(closingAmount) || 0; const difference = closingValue - expectedAmount; return (

Cerrar Caja

{/* Expected Amount */}

Monto esperado en caja

{formatCurrency(expectedAmount)}

Apertura: {formatCurrency(Number(register.openingAmount))} + Ventas efectivo:{" "} {formatCurrency(register.totalCashSales || 0)}

{/* Closing Amount Input */}
setClosingAmount(e.target.value)} min={0} step={0.01} disabled={actionLoading} />
{/* Difference Display */} {closingAmount && (
0 ? "bg-blue-50" : "bg-red-50" )} >

0 ? "text-blue-600" : "text-red-600" )} > {difference === 0 ? "Cuadre perfecto" : difference > 0 ? "Sobrante" : "Faltante"}

0 ? "text-blue-700" : "text-red-700" )} > {formatCurrency(Math.abs(difference))}

)} {/* Notes */}
setClosingNotes(e.target.value)} disabled={actionLoading} />
{error && (
{error}
)}
); } // Register is closed if (!register) { return (

Caja Cerrada

Abre la caja para comenzar a vender

{error && (
{error}
)}
); } // Register is open return (

Caja Abierta

Por {register.user.firstName} {register.user.lastName}

{/* Current Totals */}

Ventas hoy

{register._count.sales}

Efectivo esperado

{formatCurrency(register.expectedAmount || 0)}

{/* Payment Breakdown */} {register.paymentBreakdown && Object.keys(register.paymentBreakdown).length > 0 && (
{register.paymentBreakdown.CASH !== undefined && ( Efectivo: {formatCurrency(register.paymentBreakdown.CASH)} )} {register.paymentBreakdown.CARD !== undefined && ( Tarjeta: {formatCurrency(register.paymentBreakdown.CARD)} )} {register.paymentBreakdown.TRANSFER !== undefined && ( Transferencia:{" "} {formatCurrency(register.paymentBreakdown.TRANSFER)} )}
)} {error && (
{error}
)}
); }