"use client"; import Link from "next/link"; import Image from "next/image"; import { usePathname } from "next/navigation"; import clsx from "clsx"; import { LogIn, UserRound, RotateCw, BookOpen, MoreHorizontal, Moon, Sun, } from "lucide-react"; import { useEffect, useState } from "react"; import { useDashboardStore, useProAccess } from "@/hooks/useDashboardStore"; import { useI18n } from "@/hooks/useI18n"; function parseExpiryInfo(raw?: string | null) { const text = String(raw || "").trim(); if (!text) return null; const dt = new Date(text); if (Number.isNaN(dt.getTime())) return null; const diffMs = dt.getTime() - Date.now(); const daysLeft = Math.ceil(diffMs / 86_400_000); return { date: dt, daysLeft, expired: diffMs <= 0, }; } export function HeaderBar({ refreshAction, refreshSpinning, }: { refreshAction?: () => void | Promise; refreshSpinning?: boolean; }) { const store = useDashboardStore(); const { proAccess } = useProAccess(); const { locale, t, toggleLocale } = useI18n(); const pathname = usePathname(); const [theme, setTheme] = useState<"dark" | "light">("dark"); const isAuthenticated = proAccess.authenticated; const docsHref = "/docs/intro"; const docsActive = pathname?.startsWith("/docs"); const navItems = [ { href: "/", label: locale === "en-US" ? "Dashboard" : "总览", active: pathname === "/", }, ]; const isRefreshing = refreshSpinning ?? store.loadingState.refresh; const handleRefresh = () => { if (refreshAction) { return void refreshAction(); } return void store.refreshAll(); }; const accountHref = isAuthenticated ? "/account" : "/auth/login?next=%2Faccount"; const accountAria = isAuthenticated ? t("header.accountAria") : t("header.signInAria"); const effectiveExpiry = proAccess.subscriptionActive ? proAccess.subscriptionTotalExpiresAt || proAccess.subscriptionExpiresAt : proAccess.subscriptionExpiresAt; const expiryInfo = parseExpiryInfo(effectiveExpiry); const hasQueuedExtension = Boolean( proAccess.subscriptionActive && proAccess.subscriptionQueuedDays > 0, ); const showRenewReminder = isAuthenticated && !proAccess.loading && !hasQueuedExtension && ((proAccess.subscriptionActive && expiryInfo && expiryInfo.daysLeft <= 3) || (!proAccess.subscriptionActive && Boolean(expiryInfo))); const renewReminderLabel = !showRenewReminder ? "" : !proAccess.subscriptionActive ? locale === "en-US" ? "Pro expired" : "Pro 已到期" : locale === "en-US" ? `Pro ${Math.max(expiryInfo?.daysLeft || 0, 0)}d left` : `Pro 还剩 ${Math.max(expiryInfo?.daysLeft || 0, 0)} 天`; useEffect(() => { const savedTheme = typeof window !== "undefined" ? window.localStorage.getItem("polyweather_theme") : null; const nextTheme = savedTheme === "light" ? "light" : "dark"; setTheme(nextTheme); document.documentElement.classList.toggle("dark", nextTheme === "dark"); document.documentElement.classList.toggle("light", nextTheme === "light"); }, []); const toggleTheme = () => { const nextTheme = theme === "dark" ? "light" : "dark"; setTheme(nextTheme); document.documentElement.classList.toggle("dark", nextTheme === "dark"); document.documentElement.classList.toggle("light", nextTheme === "light"); window.localStorage.setItem("polyweather_theme", nextTheme); }; return (

PolyWeather

{t("header.subtitle")}
{t("header.live")}
{t("header.docs")} {isAuthenticated ? : } {showRenewReminder ? ( {renewReminderLabel} ) : null}
); }