"use client"; import { useState } from "react"; import { Notification } from "./ui"; export function PaymentCheckoutButton({ reference }: Readonly<{ reference: string }>) { const [pending, setPending] = useState(false); const [message, setMessage] = useState(null); async function beginCheckout() { setPending(true); setMessage(null); try { const response = await fetch(`/api/orders/${encodeURIComponent(reference)}/checkout`, { body: JSON.stringify({ idempotencyKey: crypto.randomUUID() }), headers: { "content-type": "application/json" }, method: "POST", }); const payload: unknown = await response.json(); const checkoutUrl = readCheckoutUrl(payload); if (!response.ok || checkoutUrl === null) { setMessage(readApiMessage(payload)); return; } window.location.assign(checkoutUrl); } catch { setMessage("The payment checkout could not be started."); } finally { setPending(false); } } return (
{message === null ? null : (

{message}

)}
); } function readCheckoutUrl(value: unknown): string | null { if ( typeof value === "object" && value !== null && "data" in value && typeof value.data === "object" && value.data !== null && "checkoutUrl" in value.data && typeof value.data.checkoutUrl === "string" && isSafeCheckoutUrl(value.data.checkoutUrl) ) { return value.data.checkoutUrl; } return null; } function isSafeCheckoutUrl(value: string): boolean { if (value.startsWith("/") && !value.startsWith("//")) return true; try { return new URL(value).protocol === "https:"; } catch { return false; } } function readApiMessage(value: unknown): string { if ( typeof value === "object" && value !== null && "error" in value && typeof value.error === "object" && value.error !== null && "message" in value.error && typeof value.error.message === "string" ) { return value.error.message; } return "The payment checkout could not be started."; }