Files
PolyWeather/frontend/components/dashboard/HeaderBar.tsx
T

118 lines
3.2 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import clsx from "clsx";
import { LogIn, UserRound } from "lucide-react";
import { useDashboardStore } from "@/hooks/useDashboardStore";
import { useI18n } from "@/hooks/useI18n";
import {
getSupabaseBrowserClient,
hasSupabasePublicEnv,
} from "@/lib/supabase/client";
export function HeaderBar() {
const store = useDashboardStore();
const { locale, setLocale, t } = useI18n();
const [isAuthenticated, setIsAuthenticated] = useState(false);
const supabaseReady = hasSupabasePublicEnv();
useEffect(() => {
let mounted = true;
if (!supabaseReady) {
setIsAuthenticated(false);
return;
}
const supabase = getSupabaseBrowserClient();
void supabase.auth.getSession().then(({ data }) => {
if (!mounted) return;
setIsAuthenticated(Boolean(data.session?.user?.id));
});
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((_event, session) => {
if (!mounted) return;
setIsAuthenticated(Boolean(session?.user?.id));
});
return () => {
mounted = false;
subscription.unsubscribe();
};
}, [supabaseReady]);
const accountHref = isAuthenticated
? "/account"
: "/auth/login?next=%2Faccount";
const accountLabel = isAuthenticated ? t("header.account") : t("header.signIn");
const accountAria = isAuthenticated
? t("header.accountAria")
: t("header.signInAria");
return (
<header className="header">
<div className="brand">
<h1>PolyWeather</h1>
<span className="subtitle">{t("header.subtitle")}</span>
</div>
<div className="header-right">
<div className="lang-switch" role="group" aria-label={t("header.langAria")}>
<button
type="button"
className={clsx("lang-btn", locale === "zh-CN" && "active")}
onClick={() => setLocale("zh-CN")}
>
{t("header.langZh")}
</button>
<button
type="button"
className={clsx("lang-btn", locale === "en-US" && "active")}
onClick={() => setLocale("en-US")}
>
{t("header.langEn")}
</button>
</div>
<Link
href={accountHref}
className="account-btn"
title={accountAria}
aria-label={accountAria}
>
{isAuthenticated ? <UserRound size={14} /> : <LogIn size={14} />}
<span>{accountLabel}</span>
</Link>
<button
type="button"
className="info-btn"
title={t("header.infoAria")}
aria-label={t("header.infoAria")}
onClick={store.openGuide}
>
{t("header.info")}
</button>
<div className="live-badge" id="liveBadge">
<span className="pulse-dot" />
<span>{t("header.live")}</span>
</div>
<button
type="button"
className={clsx("refresh-btn", store.loadingState.refresh && "spinning")}
title={t("header.refreshAria")}
aria-label={t("header.refreshAria")}
onClick={() => void store.refreshAll()}
>
</button>
</div>
</header>
);
}