- Add Ko-fi webhook (/api/webhooks/kofi) with upsert by (provider, external_user_id) • Computes renews_at = timestamp + 1 calendar month + 1 day • Preserves first started_at; stores raw payload; canonicalizes by email when available - Add Ko-fi claim flow • POST /api/support/kofi/claim/start — sends verification email via SMTP • GET /api/support/kofi/claim/verify — finalizes link (sets app_user), redirects to /portal/account • POST /api/support/kofi/unlink — clears app_user on Ko-fi rows - Add derive-on-read membership logic • /lib/memberships.ts — single source of truth for badges & “active” state • /api/support/badges — thin wrapper that returns per-provider badges - Account UI • components/account/SupporterBadges.tsx — renders provider badges (Ko-fi now; extensible) • components/account/ConnectKofi.tsx — “Link Ko-fi” form (email → verify link) • components/account/LinkStatus.tsx — success/error banner on return • app/portal/account/AccountPanel.tsx — integrates badges, link panel, and banner - Config/env • Requires: DIRECTUS_URL, DIRECTUS_TOKEN_ADMIN_SUPPORTER, KOFI_VERIFY_TOKEN • SMTP: SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASS, EMAIL_FROM • APP_ORIGIN used to build absolute verify URLs - Misc • Fixed import to use @/lib/memberships • No cron required; UI derives active state via status === active && renews_at >= now Refs: beta readiness for Ko-fi supporters
28 lines
793 B
TypeScript
28 lines
793 B
TypeScript
// /components/account/LinkStatus.tsx
|
||
"use client";
|
||
|
||
import { useSearchParams } from "next/navigation";
|
||
|
||
export default function LinkStatus() {
|
||
const sp = useSearchParams();
|
||
const linked = sp.get("linked");
|
||
if (linked !== "kofi") return null;
|
||
|
||
const isOk = sp.get("ok") === "1";
|
||
const isErr = sp.get("error") === "1";
|
||
|
||
if (!isOk && !isErr) return null;
|
||
|
||
return (
|
||
<div
|
||
className={[
|
||
"mb-3 rounded-md border p-3 text-sm",
|
||
isOk
|
||
? "border-emerald-300/50 bg-emerald-50 text-emerald-900"
|
||
: "border-red-300/50 bg-red-50 text-red-900",
|
||
].join(" ")}
|
||
>
|
||
{isOk ? "Ko-fi successfully linked to your account." : "Couldn’t verify that Ko-fi link. Please try again."}
|
||
</div>
|
||
);
|
||
}
|