"use client"; import { useRouter } from "next/navigation"; import { useState } from "react"; type ExtensionRequest = { id: string; status: string; message: string; requestedAt: string; processedAt: string | null; adminNote: string | null; }; type ExtensionUsage = { used: number; limit: number; remaining: number; requests: ExtensionRequest[]; }; type Props = { initialUsage: ExtensionUsage; }; export function PlanBillingActions({ initialUsage }: Props) { const router = useRouter(); const [usage, setUsage] = useState(initialUsage); const [cancelling, setCancelling] = useState(false); const [requesting, setRequesting] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); async function handleCancelPlan() { if ( !confirm( "Cancel your Pro plan? You will be moved to the free plan immediately and lose Pro benefits.", ) ) { return; } setCancelling(true); setError(null); setSuccess(null); try { const res = await fetch("/api/account/cancel-subscription", { method: "POST" }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to cancel subscription"); router.refresh(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to cancel subscription"); } finally { setCancelling(false); } } async function handleQuotaRequest() { if (usage.remaining <= 0) return; const reason = prompt( "Optional: tell us why you need a quota reset or extension (leave blank to skip).", ); if (reason === null) return; setRequesting(true); setError(null); setSuccess(null); try { const res = await fetch("/api/account/quota-extension-request", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: reason }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || "Failed to submit request"); setUsage({ used: data.used, limit: data.limit, remaining: data.remaining, requests: data.requests ?? usage.requests, }); setSuccess( `Request submitted. ${data.used} of ${data.limit} extension requests used this year. Support will process it shortly.`, ); router.refresh(); } catch (err) { setError(err instanceof Error ? err.message : "Failed to submit request"); } finally { setRequesting(false); } } const hasPending = usage.requests.some((r) => r.status === "PENDING"); return (

Extension requests this year:{" "} {usage.used} / {usage.limit} {usage.remaining > 0 ? ( · {usage.remaining} remaining ) : ( · limit reached )}

{error && (
{error}
)} {success && (
{success}
)}
{usage.requests.length > 0 && (

Request history

    {usage.requests.slice(0, 5).map((req) => (
  • {new Date(req.requestedAt).toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric", })} {req.status}
    {req.message &&

    {req.message}

    }

    ID: {req.id}

  • ))}
)}

Pro users may request up to 5 manual quota resets or extensions per calendar year. See our{" "} Terms of Service .

); }