"use client"; import { useState, useEffect, useCallback } from "react"; import NextLink from "next/link"; import { Link, useLocale, usePathname, useRouter, useTranslation } from "@/app/digital/i18n/navigation"; import { getStoredUserEmail } from "@/app/digital/lib/pocketbase"; import { useCrossSiteUrls } from "@/app/digital/lib/useCrossSiteUrls"; import AuthModal from "./AuthModal"; import ThemeToggle from "./ThemeToggle"; import UserAvatar from "./UserAvatar"; type NavItem = | { labelKey: "roadmap" | "tools" | "resources"; href: string; hash: string } | { labelKey: "community"; href: string; external: true }; export default function Header() { const { t } = useTranslation("common"); const { t: tNav } = useTranslation("nav"); const locale = useLocale(); const pathname = usePathname(); const router = useRouter(); const [mobileOpen, setMobileOpen] = useState(false); const [authOpen, setAuthOpen] = useState(false); const [userEmail, setUserEmail] = useState(null); const [vip, setVip] = useState(false); const { vipUrl } = useCrossSiteUrls(); const navLinks: NavItem[] = [ { labelKey: "roadmap", href: "/#roadmap", hash: "roadmap" }, { labelKey: "tools", href: "/#tools", hash: "tools" }, { labelKey: "resources", href: "/#resources", hash: "resources" }, { labelKey: "community", href: vipUrl, external: true }, ]; const fetchAuthAndVip = useCallback(async () => { try { const meRes = await fetch("/api/digital/auth/me", { credentials: "include" }); const meData = await meRes.json(); if (meData?.user && meData?.token) { const { pbSaveAuth } = await import("@/app/digital/lib/pocketbase"); pbSaveAuth(meData.token, { id: meData.user.id, email: meData.user.email }); setUserEmail(meData.user.email); const vipRes = await fetch( `/api/digital/vip/check?email=${encodeURIComponent(meData.user.email)}`, { credentials: "include" } ); const vipData = await vipRes.json(); setVip(vipData?.vip === true); } else { setUserEmail(getStoredUserEmail()); setVip(false); } } catch { /* ignore */ } }, []); useEffect(() => { fetchAuthAndVip(); }, [fetchAuthAndVip]); useEffect(() => { const onVipUpdated = () => fetchAuthAndVip(); const onAuthSuccess = () => fetchAuthAndVip(); const onAuthUpdated = () => fetchAuthAndVip(); window.addEventListener("vip:updated", onVipUpdated); window.addEventListener("auth:success", onAuthSuccess); window.addEventListener("auth:updated", onAuthUpdated); return () => { window.removeEventListener("vip:updated", onVipUpdated); window.removeEventListener("auth:success", onAuthSuccess); window.removeEventListener("auth:updated", onAuthUpdated); }; }, [fetchAuthAndVip]); const isGuideHome = pathname === "/"; const navClass = (active: boolean) => `flex items-center gap-1.5 px-3 py-2 rounded-full text-sm font-medium transition-colors whitespace-nowrap shrink-0 ${ active ? "text-gray-900 dark:text-gray-100 bg-gray-100 dark:bg-gray-800" : "text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800" }`; return (
🌏 {t("parentSiteName")} / {t("siteName")}
{userEmail ? ( { setUserEmail(null); setVip(false); router.replace("/"); }} /> ) : ( )} {t("explore")}
{mobileOpen && (
setMobileOpen(false)} className="flex items-center gap-2 px-4 py-3 rounded-xl text-sm font-medium text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800" > 🌏 {tNav("mainSite")} {navLinks.map((link) => "external" in link && link.external ? ( setMobileOpen(false)} className="flex items-center gap-2 px-4 py-3 rounded-xl text-sm font-medium text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800" > {tNav(link.labelKey)} ) : ( setMobileOpen(false)} className="flex items-center gap-2 px-4 py-3 rounded-xl text-sm font-medium text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800" > {tNav(link.labelKey)} ) )} {userEmail ? (
{ setUserEmail(null); setVip(false); setMobileOpen(false); router.replace("/"); }} /> {userEmail}
) : ( )}
)} setAuthOpen(false)} onSuccess={() => fetchAuthAndVip()} />
); }