's'
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user