44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState } from 'react';
|
||
|
|
import { useRouter } from 'next/navigation';
|
||
|
|
|
||
|
|
export function UpgradeButton({ plan, label, disabled }: { plan: string; label: string; disabled?: boolean }) {
|
||
|
|
const router = useRouter();
|
||
|
|
const [busy, setBusy] = useState(false);
|
||
|
|
const [error, setError] = useState<string | null>(null);
|
||
|
|
|
||
|
|
async function upgrade() {
|
||
|
|
setBusy(true);
|
||
|
|
setError(null);
|
||
|
|
try {
|
||
|
|
const res = await fetch('/api/billing/checkout', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ plan }),
|
||
|
|
});
|
||
|
|
if (res.status === 401) {
|
||
|
|
router.push('/login?next=/pricing');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!res.ok) throw new Error(`Checkout failed (${res.status})`);
|
||
|
|
const data = (await res.json()) as { url: string };
|
||
|
|
router.push(data.url.replace(/^https?:\/\/[^/]+/, ''));
|
||
|
|
router.refresh();
|
||
|
|
} catch (e) {
|
||
|
|
setError(e instanceof Error ? e.message : 'Checkout failed');
|
||
|
|
} finally {
|
||
|
|
setBusy(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="mt-6">
|
||
|
|
<button type="button" className="btn-primary w-full" onClick={upgrade} disabled={busy || disabled}>
|
||
|
|
{busy ? 'Working…' : label}
|
||
|
|
</button>
|
||
|
|
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|