"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; /** * Banner shown after a return from Stripe Checkout. * * ?paid=1 → green success banner. The webhook may or may * not have processed yet, so we phrase the message * as "Payment received, status will update shortly" * and don't claim the status is already paid. A * light auto-refresh after a few seconds nudges * the page to pick up the new status badge. * * ?cancelled=1 → neutral grey banner: "Payment cancelled". The * invoice stays in 'open' state. * * The banner cleans up the query params from the URL so a page * reload doesn't repeat the message. We use router.replace() to * keep history clean. */ export function PaymentStatusBanner() { const router = useRouter(); const t = useTranslations("customerBilling"); const [state, setState] = useState<"paid" | "cancelled" | null>(null); useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.has("paid")) { setState("paid"); // The webhook usually arrives before the browser redirect // completes, so the page often renders with status='paid' // on first load and this refresh is a no-op. In the rare // case where it arrives slightly after, a short refresh // picks up the status flip. 1.5s is comfortable for both. const timer = setTimeout(() => { router.refresh(); }, 1500); // Strip the query string out of the URL. const cleanUrl = window.location.pathname; window.history.replaceState({}, "", cleanUrl); return () => clearTimeout(timer); } else if (params.has("cancelled")) { setState("cancelled"); const cleanUrl = window.location.pathname; window.history.replaceState({}, "", cleanUrl); } }, [router]); if (state === "paid") { return (