"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { Link, useLocale, useTranslation } from "@/app/digital/i18n/navigation"; import AuthModal from "@/app/digital/components/AuthModal"; import DigitalThemeIcon, { type IconName } from "@/app/digital/components/DigitalThemeIcon"; import { getStoredToken, getStoredUser, pbLogout, pbSaveAuth } from "@/app/digital/lib/pocketbase"; import { useCrossSiteUrls } from "@/app/digital/lib/useCrossSiteUrls"; type ProfileUser = { id: string; email: string; }; type AccountState = { user: ProfileUser | null; vip: boolean; expiresAt: string | null; }; type ActionItem = { icon: IconName; emoji: string; title: string; description: string; href: string; tag: string; external?: boolean; }; function getAvatarLetter(email: string): string { const local = email.split("@")[0]; return (local || "?").slice(0, 1).toUpperCase(); } function formatDate(value: string, locale: string): string { const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return new Intl.DateTimeFormat(locale === "zh" ? "zh-CN" : "en-US", { year: "numeric", month: "2-digit", day: "2-digit", }).format(date); } function ActionCard({ item }: { item: ActionItem }) { const content = ( <>

{item.title}

{item.tag}

{item.description}

); const className = "dn-action-card group flex min-h-[150px] items-start gap-4 rounded-2xl border border-slate-200 bg-white p-5 text-left shadow-sm transition-all hover:border-sky-300 hover:shadow-md dark:border-slate-700 dark:bg-slate-900 dark:hover:border-sky-600"; if (item.external) { return ( {content} ); } return ( {content} ); } export default function ProfileContent() { const locale = useLocale(); const { t } = useTranslation("profile"); const { vipUrl } = useCrossSiteUrls(); const [account, setAccount] = useState({ user: null, vip: false, expiresAt: null, }); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [authOpen, setAuthOpen] = useState(false); const refreshAccount = useCallback(async (manual = false) => { if (manual) setRefreshing(true); else setLoading(true); try { const meRes = await fetch("/api/digital/auth/me", { credentials: "include", cache: "no-store", }); const meData = await meRes.json().catch(() => null); let user = meData?.user?.id && meData?.user?.email ? { id: meData.user.id as string, email: meData.user.email as string } : null; if (!user) { const storedUser = getStoredUser(); const storedToken = getStoredToken(); if (storedUser && storedToken) { user = { id: storedUser.id, email: storedUser.email }; await fetch("/api/digital/auth/sync-session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: storedToken, record: storedUser }), credentials: "include", }).catch(() => null); } else { setAccount({ user: null, vip: false, expiresAt: null }); return; } } if (meData?.token) { pbSaveAuth(meData.token, user); } const vipRes = await fetch(`/api/digital/vip/check?email=${encodeURIComponent(user.email)}`, { credentials: "include", cache: "no-store", }); const vipData = await vipRes.json().catch(() => null); setAccount({ user, vip: vipData?.vip === true, expiresAt: typeof vipData?.expires_at === "string" ? vipData.expires_at : null, }); } catch { const storedUser = getStoredUser(); setAccount({ user: storedUser ? { id: storedUser.id, email: storedUser.email } : null, vip: false, expiresAt: null, }); } finally { setLoading(false); setRefreshing(false); } }, []); useEffect(() => { refreshAccount(); }, [refreshAccount]); const handleLogout = async () => { await pbLogout(); setAccount({ user: null, vip: false, expiresAt: null }); window.dispatchEvent(new CustomEvent("auth:updated")); }; const primaryActions = useMemo(() => [ { icon: "globe", emoji: "🌐", title: t("actions.community.title"), description: t("actions.community.description"), href: vipUrl, tag: account.vip ? t("tags.active") : t("tags.apply"), external: true, }, { icon: "course", emoji: "🎓", title: t("actions.course.title"), description: t("actions.course.description"), href: "/course", tag: account.vip ? t("tags.unlocked") : t("tags.trial"), }, { icon: "book", emoji: "📚", title: t("actions.ebook.title"), description: t("actions.ebook.description"), href: "/ebook", tag: t("tags.ready"), }, { icon: "phone", emoji: "📱", title: t("actions.app.title"), description: t("actions.app.description"), href: "/app", tag: t("tags.download"), }, ], [account.vip, t, vipUrl]); const workflowActions = useMemo(() => [ { icon: "compass", emoji: "🧭", title: t("workflow.roadmap.title"), description: t("workflow.roadmap.description"), href: "/#roadmap", tag: t("tags.start"), }, { icon: "tool", emoji: "🛠️", title: t("workflow.tools.title"), description: t("workflow.tools.description"), href: "/#tools", tag: t("tags.open"), }, { icon: "file", emoji: "📄", title: t("workflow.resources.title"), description: t("workflow.resources.description"), href: "/#resources", tag: t("tags.curated"), }, { icon: "check", emoji: "✅", title: t("workflow.privacy.title"), description: t("workflow.privacy.description"), href: "/privacy", tag: t("tags.policy"), }, ], [t]); if (loading) { return (
); } if (!account.user) { return (

{t("signedOutBadge")}

{t("signedOutTitle")}

{t("signedOutDescription")}

{t("homeCta")}
setAuthOpen(false)} onSuccess={() => refreshAccount(true)} />
); } const expiryText = account.vip ? account.expiresAt ? formatDate(account.expiresAt, locale) : t("lifetime") : t("notVip"); return (

{t("eyebrow")}

{t("title")}

{t("description")}

{t("loggedIn")} {account.vip ? t("vipActive") : t("vipInactive")} {t("expiry")}: {expiryText}

{t("accessEyebrow")}

{t("accessTitle")}

{primaryActions.map((item) => ( ))}

{t("workflowEyebrow")}

{t("workflowTitle")}

{workflowActions.map((item) => ( ))}
); }