"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { startMidtransPaymentAction } from "@/features/booking/actions"; interface SnapCallbacks { onSuccess?: (result: unknown) => void; onPending?: (result: unknown) => void; onError?: (result: unknown) => void; onClose?: () => void; } interface SnapApi { pay: (token: string, callbacks?: SnapCallbacks) => void; } declare global { interface Window { snap?: SnapApi; } } const SCRIPT_ID = "midtrans-snap-script"; function loadSnapScript(snapJsUrl: string, clientKey: string): Promise { return new Promise((resolve, reject) => { if (typeof window === "undefined") { reject(new Error("Snap hanya bisa dimuat di browser")); return; } if (window.snap) { resolve(); return; } const existing = document.getElementById(SCRIPT_ID); if (existing) { existing.addEventListener("load", () => resolve()); existing.addEventListener("error", () => reject(new Error("Gagal memuat Snap.js")) ); return; } const script = document.createElement("script"); script.id = SCRIPT_ID; script.src = snapJsUrl; script.async = true; script.setAttribute("data-client-key", clientKey); script.onload = () => resolve(); script.onerror = () => reject(new Error("Gagal memuat Snap.js")); document.body.appendChild(script); }); } interface MidtransPayButtonProps { tripId: string; } export function MidtransPayButton({ tripId }: MidtransPayButtonProps) { const router = useRouter(); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); async function handleClick() { setLoading(true); setError(""); const result = await startMidtransPaymentAction(tripId); if ("error" in result) { setError(result.error); setLoading(false); return; } try { await loadSnapScript(result.snapJsUrl, result.clientKey); } catch (e) { setError(e instanceof Error ? e.message : "Gagal memuat pembayaran"); setLoading(false); return; } if (!window.snap) { setError("Snap belum siap, refresh halaman dan coba lagi"); setLoading(false); return; } window.snap.pay(result.snapToken, { onSuccess: () => { // Webhook server akan tetap jadi sumber kebenaran. Refresh page untuk pull state baru. router.refresh(); }, onPending: () => router.refresh(), onError: () => { setError( "Pembayaran gagal diproses. Coba lagi atau pakai metode lain." ); router.refresh(); }, onClose: () => { // User menutup popup tanpa menyelesaikan. Refresh saja, kalau status berubah // (mis. user sudah bayar VA) callback dari Midtrans akan datang ke webhook. router.refresh(); }, }); setLoading(false); } return (
{error && (
{error}
)}

Bayar pakai BCA VA, GoPay, QRIS, kartu, dan lainnya. Status terupdate otomatis setelah pembayaran terkonfirmasi gateway.

); }