This commit is contained in:
eric
2026-03-12 19:54:58 -05:00
parent 14bbd3b306
commit f66859c032
31 changed files with 1132 additions and 312 deletions

View File

@@ -7,6 +7,7 @@ import { getNavLinks } from "@/config";
import AuthModal from "./AuthModal";
import ThemeToggle from "./ThemeToggle";
import SiteMenu from "./SiteMenu";
import UserAvatar from "./UserAvatar";
export default function NavbarComponent() {
const { t } = useTranslation("common");
@@ -18,33 +19,42 @@ export default function NavbarComponent() {
const [menuOpen, setMenuOpen] = useState(false);
const [authOpen, setAuthOpen] = useState(false);
const [userEmail, setUserEmail] = useState<string | null>(null);
const [userVip, setUserVip] = useState(false);
const navLinks = getNavLinks();
useEffect(() => {
let mounted = true;
(async () => {
try {
const res = await fetch("/api/auth/me", { credentials: "include" });
const data = await res.json();
if (!mounted) return;
if (data?.user && data?.token) {
const { pbSaveAuth } = await import("@/app/lib/pocketbase");
pbSaveAuth(data.token, { id: data.user.id, email: data.user.email });
setUserEmail(data.user.email);
return;
}
} catch {
/* ignore */
const fetchAuth = useCallback(async () => {
try {
const res = await fetch("/api/auth/me", { credentials: "include", cache: "no-store" });
const data = await res.json();
if (data?.user && data?.token) {
const { pbSaveAuth } = await import("@/app/lib/pocketbase");
pbSaveAuth(data.token, { id: data.user.id, email: data.user.email });
setUserEmail(data.user.email);
setUserVip(!!data.user.vip);
return;
}
if (mounted) setUserEmail(getStoredUserEmail());
})();
return () => { mounted = false; };
} catch {
/* ignore */
}
setUserEmail(getStoredUserEmail());
setUserVip(false);
}, []);
useEffect(() => {
fetchAuth();
}, [fetchAuth]);
useEffect(() => {
const onAuthUpdated = () => fetchAuth();
window.addEventListener("auth:updated", onAuthUpdated);
return () => window.removeEventListener("auth:updated", onAuthUpdated);
}, [fetchAuth]);
const handleLogout = useCallback(async () => {
await pbLogout();
setUserEmail(null);
setUserVip(false);
}, []);
const isActive = useCallback((href: string) => {
@@ -114,12 +124,7 @@ export default function NavbarComponent() {
<span className="hidden sm:block max-w-[120px] truncate text-sm text-gray-600 dark:text-gray-400">
{userEmail}
</span>
<button
onClick={handleLogout}
className="rounded-full border border-gray-200 dark:border-gray-700 px-2 sm:px-4 py-2 text-xs sm:text-sm font-medium text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors whitespace-nowrap"
>
{t("logout")}
</button>
<UserAvatar email={userEmail} isVip={userVip} onLogout={() => { setUserEmail(null); setUserVip(false); }} />
</div>
) : null}
<button
@@ -182,10 +187,8 @@ export default function NavbarComponent() {
</button>
{userEmail ? (
<div className="pt-2 border-t border-gray-100 dark:border-gray-800 flex items-center justify-between px-4 py-2.5 rounded-lg bg-gray-50 dark:bg-gray-800">
<UserAvatar email={userEmail} isVip={userVip} onLogout={() => { handleLogout(); setMobileOpen(false); }} />
<span className="truncate text-sm text-gray-600 dark:text-gray-400">{userEmail}</span>
<button onClick={() => { handleLogout(); setMobileOpen(false); }} className="text-sm font-medium text-[#ff4d4f]">
{t("logout")}
</button>
</div>
) : null}
</div>