"use client"; import { RiEditLine } from "@remixicon/react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState, useTransition } from "react"; import { toast } from "sonner"; import { updateInvoicePaymentStatusAction, updatePaymentDateAction, } from "@/app/(dashboard)/cartoes/[cartaoId]/fatura/actions"; import DotIcon from "@/components/dot-icon"; import MoneyValues from "@/components/money-values"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { INVOICE_PAYMENT_STATUS, INVOICE_STATUS_BADGE_VARIANT, INVOICE_STATUS_DESCRIPTION, INVOICE_STATUS_LABEL, type InvoicePaymentStatus, } from "@/lib/faturas"; import { cn } from "@/lib/utils/ui"; import { EditPaymentDateDialog } from "./edit-payment-date-dialog"; type InvoiceSummaryCardProps = { cartaoId: string; period: string; cardName: string; cardBrand: string | null; cardStatus: string | null; closingDay: string; dueDay: string; periodLabel: string; totalAmount: number; limitAmount: number | null; invoiceStatus: InvoicePaymentStatus; paymentDate: Date | null; logo?: string | null; actions?: React.ReactNode; }; const BRAND_ASSETS: Record = { visa: "/bandeiras/visa.svg", mastercard: "/bandeiras/mastercard.svg", amex: "/bandeiras/amex.svg", american: "/bandeiras/amex.svg", elo: "/bandeiras/elo.svg", hipercard: "/bandeiras/hipercard.svg", hiper: "/bandeiras/hipercard.svg", }; const resolveBrandAsset = (brand: string) => { const normalized = brand.trim().toLowerCase(); const match = ( Object.keys(BRAND_ASSETS) as Array ).find((entry) => normalized.includes(entry)); return match ? BRAND_ASSETS[match] : null; }; const actionLabelByStatus: Record = { [INVOICE_PAYMENT_STATUS.PENDING]: "Marcar como paga", [INVOICE_PAYMENT_STATUS.PAID]: "Desfazer pagamento", }; const actionVariantByStatus: Record< InvoicePaymentStatus, "default" | "outline" > = { [INVOICE_PAYMENT_STATUS.PENDING]: "default", [INVOICE_PAYMENT_STATUS.PAID]: "outline", }; const formatDay = (value: string) => value.padStart(2, "0"); const resolveLogoPath = (logo?: string | null) => { if (!logo) return null; if ( logo.startsWith("http://") || logo.startsWith("https://") || logo.startsWith("data:") ) { return logo; } return logo.startsWith("/") ? logo : `/logos/${logo}`; }; const getCardStatusDotColor = (status: string | null) => { if (!status) return "bg-gray-400"; const normalizedStatus = status.toLowerCase(); if (normalizedStatus === "ativo" || normalizedStatus === "active") { return "bg-success"; } return "bg-gray-400"; }; export function InvoiceSummaryCard({ cartaoId, period, cardName, cardBrand, cardStatus, closingDay, dueDay, periodLabel, totalAmount, limitAmount, invoiceStatus, paymentDate: initialPaymentDate, logo, actions, }: InvoiceSummaryCardProps) { const router = useRouter(); const [isPending, startTransition] = useTransition(); const [paymentDate, setPaymentDate] = useState( initialPaymentDate ?? new Date(), ); // Atualizar estado quando initialPaymentDate mudar useEffect(() => { if (initialPaymentDate) { setPaymentDate(initialPaymentDate); } }, [initialPaymentDate]); const logoPath = useMemo(() => resolveLogoPath(logo), [logo]); const brandAsset = useMemo( () => (cardBrand ? resolveBrandAsset(cardBrand) : null), [cardBrand], ); const limitLabel = useMemo(() => { if (typeof limitAmount !== "number") return "—"; return limitAmount.toLocaleString("pt-BR", { style: "currency", currency: "BRL", maximumFractionDigits: 2, }); }, [limitAmount]); const targetStatus = invoiceStatus === INVOICE_PAYMENT_STATUS.PAID ? INVOICE_PAYMENT_STATUS.PENDING : INVOICE_PAYMENT_STATUS.PAID; const handleAction = () => { startTransition(async () => { const result = await updateInvoicePaymentStatusAction({ cartaoId, period, status: targetStatus, paymentDate: targetStatus === INVOICE_PAYMENT_STATUS.PAID ? paymentDate.toISOString().split("T")[0] : undefined, }); if (result.success) { toast.success(result.message); router.refresh(); return; } toast.error(result.error); }); }; const handleDateChange = (newDate: Date) => { setPaymentDate(newDate); startTransition(async () => { const result = await updatePaymentDateAction({ cartaoId, period, paymentDate: newDate.toISOString().split("T")[0] ?? "", }); if (result.success) { toast.success(result.message); router.refresh(); return; } toast.error(result.error); }); }; return (
{logoPath ? (
{`Logo
) : cardBrand ? ( {cardBrand} ) : null}
{cardName}

Fatura de {periodLabel}

{actions ?
{actions}
: null}
{/* Destaque Principal */}
} /> {INVOICE_STATUS_LABEL[invoiceStatus]} } />
{/* Informações Gerais */}
Dia {formatDay(closingDay)} } /> Dia {formatDay(dueDay)}} /> {`Bandeira {cardBrand}
) : cardBrand ? ( {cardBrand} ) : ( ) } /> {cardStatus} ) : ( ) } /> {/* Ações */}

{INVOICE_STATUS_DESCRIPTION[invoiceStatus]}

{invoiceStatus === INVOICE_PAYMENT_STATUS.PAID && ( } currentDate={paymentDate} onDateChange={handleDateChange} /> )}
); } type DetailItemProps = { label?: string; value: React.ReactNode; className?: string; }; function DetailItem({ label, value, className }: DetailItemProps) { return (
{label && ( {label} )}
{value}
); }