"use client"; import { useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { ArrowRight, Banknote, CircleAlert, CircleCheck, CircleX, } from "lucide-react"; import { decideRefundAction } from "@/features/refund/actions"; import { formatRupiah } from "@/lib/utils"; type RefundStatus = | "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED"; type Decision = "APPROVE" | "REJECT" | "SUCCEEDED" | "FAILED"; export type RefundCardData = { id: string; amount: number; currency: string; reason: string; reportedBy: "PARTICIPANT" | "ORGANIZER"; reportNote: string; initiatedBy: string; status: RefundStatus; adminNote: string | null; createdAt: Date; reviewedAt: Date | null; succeededAt: Date | null; failedAt: Date | null; reviewedBy: { id: string; name: string; email: string } | null; booking: { id: string; amount: number; status: string; trip: { id: string; title: string; date: Date }; user: { id: string; name: string; email: string }; payments: { id: string; provider: string; method: string | null; amount: number; status: string; paidAt: Date | null; }[]; }; }; function formatDate(d: Date): string { return new Date(d).toLocaleString("id-ID", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", }); } const REASON_LABEL: Record = { USER_CANCELLATION: "Peserta cancel", ORGANIZER_CANCELLED: "Organizer batalkan", TRIP_ISSUE: "Masalah trip", ADMIN_ADJUSTMENT: "Penyesuaian admin", DISPUTE_RESOLVED: "Dispute resolved", OTHER: "Lain-lain", }; export function RefundReviewCard({ refund }: { refund: RefundCardData }) { const router = useRouter(); const [openAction, setOpenAction] = useState(null); const [note, setNote] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); const paidPayment = refund.booking.payments.find( (p) => p.status === "PAID" || p.status === "REFUNDED" ); async function submit(decision: Decision) { setError(""); setLoading(true); const fd = new FormData(); fd.set("refundId", refund.id); fd.set("decision", decision); if (note.trim()) fd.set("adminNote", note); const result = await decideRefundAction(fd); setLoading(false); if (result.error) { setError(result.error); return; } setOpenAction(null); setNote(""); router.refresh(); } return (

{refund.booking.trip.title}

Dilaporkan {formatDate(refund.createdAt)} oleh{" "} {refund.reportedBy === "PARTICIPANT" ? "Peserta" : "Organizer"} {" · "} {refund.id.slice(0, 8)}…

Booking ID

{refund.booking.id}

Lihat timeline payment & refund

Isi laporan

{refund.reportNote}

{refund.adminNote && (

Catatan admin

{refund.adminNote}

)} {refund.reviewedBy && refund.reviewedAt && (

Diproses oleh {refund.reviewedBy.name} pada{" "} {formatDate(refund.reviewedAt)} {refund.succeededAt && ` · uang keluar ${formatDate(refund.succeededAt)}`} {refund.failedAt && ` · gagal ${formatDate(refund.failedAt)}`}

)} {(refund.status === "PENDING" || refund.status === "APPROVED") && (
{error && (
{error}
)} {openAction ? ( { setOpenAction(null); setNote(""); setError(""); }} onConfirm={() => submit(openAction)} /> ) : (
{refund.status === "PENDING" && ( <> )} {refund.status === "APPROVED" && ( <> )}
)}
)}
); } function ActionForm({ decision, note, setNote, loading, onCancel, onConfirm, }: { decision: Decision; note: string; setNote: (v: string) => void; loading: boolean; onCancel: () => void; onConfirm: () => void; }) { const cfg = { APPROVE: { label: "Setujui Refund", placeholder: "Catatan untuk approval (opsional)", required: false, btnLabel: "Konfirmasi Setuju", btnClass: "bg-primary-600 hover:bg-primary-700", }, REJECT: { label: "Tolak Refund", placeholder: "Alasan penolakan (wajib)", required: true, btnLabel: "Konfirmasi Tolak", btnClass: "bg-red-600 hover:bg-red-700", }, SUCCEEDED: { label: "Tandai Sudah Transfer", placeholder: "Referensi transfer / nomor mutasi bank (wajib)", required: true, btnLabel: "Tandai SUCCEEDED", btnClass: "bg-primary-600 hover:bg-primary-700", }, FAILED: { label: "Tandai Gagal", placeholder: "Alasan gagal (wajib)", required: true, btnLabel: "Tandai FAILED", btnClass: "bg-red-600 hover:bg-red-700", }, }[decision]; return (

{cfg.label}