156 lines
6.0 KiB
TypeScript
156 lines
6.0 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link";
|
|
import React, {useEffect} from 'react';
|
|
import {AlertCircle, CheckCircle2, Clock, CreditCard, LayoutGrid, LogOut, SettingsIcon, XCircle} from "lucide-react";
|
|
import {usePathname, useRouter} from "next/navigation";
|
|
import useUserStore from "@/store/user";
|
|
import useSubscribeStore from "@/store/subscribe";
|
|
import {formatSecond} from "@/utils/format";
|
|
|
|
function Header() {
|
|
const {status, remainingSeconds} = useSubscribeStore();
|
|
|
|
|
|
// 2. 根据状态获取配置(颜色、图标、文本)
|
|
const getStatusConfig = () => {
|
|
switch (status) {
|
|
case "trial":
|
|
return {
|
|
label: `Trial · ${formatSecond(remainingSeconds)}`,
|
|
className: "border-blue-200 bg-blue-50 text-blue-800 hover:bg-blue-100",
|
|
icon: <Clock className="h-3 w-3"/>
|
|
};
|
|
case "active":
|
|
return {
|
|
label: "Active",
|
|
className: "border-emerald-200 bg-emerald-50 text-emerald-800 hover:bg-emerald-100",
|
|
icon: <CheckCircle2 className="h-3 w-3"/>
|
|
};
|
|
case "past_due":
|
|
return {
|
|
label: "Payment Due",
|
|
className: "border-amber-200 bg-amber-50 text-amber-800 hover:bg-amber-100",
|
|
icon: <AlertCircle className="h-3 w-3"/>
|
|
};
|
|
case "canceled":
|
|
return {
|
|
label: remainingSeconds > 0 ? `Ends in ${formatSecond(remainingSeconds)}` : "Expired",
|
|
className: "border-slate-200 bg-slate-50 text-slate-800 hover:bg-slate-100",
|
|
icon: <XCircle className="h-3 w-3"/>
|
|
};
|
|
default:
|
|
return null; // 未加载时不显示
|
|
}
|
|
};
|
|
|
|
const config = getStatusConfig();
|
|
|
|
return (
|
|
<header className="sticky top-0 z-30 border-b border-border/60 bg-background/85 backdrop-blur-md">
|
|
<div className="container mx-auto flex h-14 max-w-6xl items-center justify-between gap-4 px-4 md:px-6">
|
|
<div className="flex min-w-0 items-center gap-2 sm:gap-5">
|
|
<Link
|
|
href="/dashboard"
|
|
className="flex shrink-0 items-center gap-2 text-sm font-semibold tracking-tight">
|
|
<div
|
|
className="inline-flex h-7 w-7 items-center justify-center rounded bg-foreground text-[11px] font-bold text-background">
|
|
S
|
|
</div>
|
|
<span className="hidden sm:inline">StoreAI</span>
|
|
</Link>
|
|
<span className="hidden h-5 w-px bg-border/60 md:inline-block" aria-hidden="true"/>
|
|
<NavTabs/>
|
|
</div>
|
|
|
|
<div className="flex shrink-0 items-center gap-3">
|
|
{config && (
|
|
<Link href="/dashboard/billing"
|
|
className={`inline-flex h-7 items-center gap-1.5 rounded-full border px-2.5 text-[11px] font-medium transition-colors ${config.className}`}>
|
|
{config.icon}
|
|
{config.label}
|
|
</Link>
|
|
)}
|
|
<span className="hidden h-5 w-px bg-border/60 md:inline-block" aria-hidden="true"/>
|
|
<UserMenu/>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* 导航栏
|
|
*/
|
|
const NavTabs = () => {
|
|
const pathname = usePathname();
|
|
const tabs = [
|
|
{href: "/dashboard", label: "Dashboard", icon: LayoutGrid},
|
|
{href: "/dashboard/setting", label: "Settings", icon: SettingsIcon},
|
|
{href: "/dashboard/billing", label: "Billing", icon: CreditCard},
|
|
];
|
|
return (
|
|
<nav className="flex items-center gap-0.5" aria-label="Dashboard navigation">
|
|
{tabs.map(item => {
|
|
const Icon = item.icon;
|
|
const isActive = item.href === "/dashboard"
|
|
? pathname === item.href
|
|
: pathname === item.href || pathname.startsWith(`${item.href}/`);
|
|
|
|
return (
|
|
<Link
|
|
key={item.href}
|
|
href={item.href}
|
|
className={`relative inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition-colors sm:px-3 sm:text-sm ${
|
|
isActive
|
|
? "text-foreground"
|
|
: "text-muted-foreground hover:bg-muted/60 hover:text-foreground"
|
|
}`}>
|
|
<Icon className="h-3.5 w-3.5"/>
|
|
<span className="hidden sm:inline">{item.label}</span>
|
|
{isActive && (
|
|
<span
|
|
aria-hidden="true"
|
|
className="absolute -bottom-3.25 left-2 right-2 h-0.5 rounded-t-full bg-foreground"
|
|
/>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
|
|
/**
|
|
* 用户信息
|
|
*/
|
|
const UserMenu = () => {
|
|
const userStore = useUserStore();
|
|
const router = useRouter();
|
|
|
|
function handleSignOut() {
|
|
userStore.logout();
|
|
router.replace("/login");
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<div className="hidden max-w-50 truncate text-xs text-muted-foreground md:inline">
|
|
{userStore.user?.email}
|
|
</div>
|
|
<div
|
|
className="cursor-pointer inline-flex h-7 items-center gap-1 rounded-md px-2 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
|
title="Sign out"
|
|
onClick={handleSignOut}>
|
|
<LogOut className="h-3 w-3"/>
|
|
<span className="hidden sm:inline">Sign out</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
|
|
export default Header
|