// components/account/ConnectKofi.tsx "use client"; import { useCallback, useMemo, useState } from "react"; export default function ConnectKofi({ email, userId, }: { email?: string | null; userId?: string | null; }) { const [value, setValue] = useState(email || ""); const [busy, setBusy] = useState(false); const [msg, setMsg] = useState(null); const [err, setErr] = useState(null); const canSubmit = useMemo( () => !!value && /\S+@\S+\.\S+/.test(value), [value] ); const startClaim = useCallback(async () => { setErr(null); setMsg(null); setBusy(true); try { const res = await fetch("/api/support/kofi/claim/start", { method: "POST", headers: { "Content-Type": "application/json", // if your auth middleware expects anything, set it here; otherwise cookies suffice "x-user-id": userId ?? "", "x-user-email": email ?? "", }, credentials: "include", body: JSON.stringify({ email: value }), }); const j = await res.json().catch(() => ({} as any)); if (!res.ok) { // Show specific errors where helpful const detail = j?.detail || j?.error || res.statusText; throw new Error( j?.error === "not_found" ? "We don’t have any Ko-fi records for that email yet. If you’re sure it’s correct, try again after your next Ko-fi payment or after we run the backfill." : String(detail || "Failed to start verification") ); } if (j?.alreadyLinked) { setMsg("This Ko-fi email is already linked to your account."); } else { setMsg( "Verification email sent! Check your inbox and click the link to finish linking Ko-fi." ); } } catch (e: any) { setErr(e?.message || "Something went wrong."); } finally { setBusy(false); } }, [value, userId, email]); const unlink = useCallback(async () => { setErr(null); setMsg(null); setBusy(true); try { const res = await fetch("/api/support/kofi/unlink", { method: "POST", headers: { "Content-Type": "application/json", "x-user-id": userId ?? "", }, credentials: "include", }); if (!res.ok) { const t = await res.text().catch(() => ""); throw new Error(t || "Unlink failed"); } setMsg("Ko-fi has been unlinked from your account."); } catch (e: any) { setErr(e?.message || "Unlink failed."); } finally { setBusy(false); } }, [userId]); return (

Link Ko-fi

Enter the email you use on Ko-fi. We’ll send a one-time verification link to confirm it’s you.

setValue(e.target.value)} disabled={busy} />
{msg && (
{msg}
)} {err && (
{err}
)}

Tip: after you verify, badges update automatically. If you don’t see a badge yet, it’ll appear the next time a Ko-fi payment webhook arrives (or after backfill).

); }