Replaced the dedicated /admin/subscriptions page with a redirect to the central admin panel’s subscriptions tab. Removed session checks, imports, and the AdminSubscriptionDashboard since routing and access are now handled centrally. This streamlines admin UX and keeps access control unified.
200 lines
7.0 KiB
TypeScript
200 lines
7.0 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
NavigationMenu,
|
|
NavigationMenuItem,
|
|
NavigationMenuLink,
|
|
NavigationMenuList,
|
|
navigationMenuTriggerStyle,
|
|
} from "@/components/ui/navigation-menu";
|
|
import { WordRotate } from "@/components/ui/word-rotate";
|
|
import { ThemeToggle } from "./theme-toggle";
|
|
import { LanguageSwitcher } from "./language-switcher";
|
|
import { MobileMenu } from "./mobile-menu";
|
|
import { NotificationBell } from "./notifications/NotificationBell";
|
|
import { MessagesBell } from "./messages/MessagesBell";
|
|
import { LoginDialog } from "./auth/login-dialog";
|
|
import { RegisterDialog } from "./auth/register-dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
|
import { cn } from "@/lib/utils";
|
|
import { useTranslations, useLocale } from "next-intl";
|
|
import { useSession } from "@/lib/hooks/use-session";
|
|
import Link from "next/link";
|
|
import { useState, useEffect } from "react";
|
|
import { LogOut, User } from "lucide-react";
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
|
export default function Header() {
|
|
const t = useTranslations("header.nav");
|
|
const locale = useLocale();
|
|
const { user, isAuthenticated, isLoading, logout } = useSession();
|
|
const [loginDialogOpen, setLoginDialogOpen] = useState(false);
|
|
const [registerDialogOpen, setRegisterDialogOpen] = useState(false);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Evitar hidratação mismatch
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
const links = [
|
|
{ href: `/${locale}/library`, label: "Library" },
|
|
{ href: `/${locale}/market`, label: t("market") },
|
|
{ href: `/${locale}/sobre`, label: t("about") },
|
|
{ href: `/${locale}/precos`, label: t("prices") },
|
|
{ href: `/${locale}/apoiar`, label: t("support"), highlight: true },
|
|
];
|
|
|
|
const navLinks = [
|
|
...links,
|
|
...(isAuthenticated && user?.userId === 1
|
|
? [{ href: `/${locale}/admin`, label: "Admin" }]
|
|
: []),
|
|
];
|
|
|
|
const handleLogout = async () => {
|
|
await logout();
|
|
};
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 w-full border-b bg-background/60 backdrop-blur supports-backdrop-filter:bg-background/60">
|
|
<div className="mx-auto flex h-16 w-full max-w-6xl items-center justify-between px-4">
|
|
{/* Logo */}
|
|
<div className="flex items-center gap-2">
|
|
<Link href="/">
|
|
<WordRotate
|
|
words={["Tibia Trade"]}
|
|
className="text-lg font-semibold tracking-tight hover:text-primary transition-colors"
|
|
/>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Desktop Navigation */}
|
|
<NavigationMenu className="hidden md:flex">
|
|
<NavigationMenuList>
|
|
{navLinks.map(({ href, label, highlight }) => (
|
|
<NavigationMenuItem key={href}>
|
|
<NavigationMenuLink asChild>
|
|
<Link
|
|
href={href}
|
|
className={cn(
|
|
navigationMenuTriggerStyle(),
|
|
"bg-transparent",
|
|
highlight &&
|
|
"bg-primary text-primary-foreground hover:bg-primary/90"
|
|
)}
|
|
>
|
|
{label}
|
|
</Link>
|
|
</NavigationMenuLink>
|
|
</NavigationMenuItem>
|
|
))}
|
|
</NavigationMenuList>
|
|
</NavigationMenu>
|
|
|
|
{/* Desktop Controls */}
|
|
<div className="hidden md:flex items-center gap-2">
|
|
<ThemeToggle />
|
|
<LanguageSwitcher />
|
|
|
|
{/* Messages */}
|
|
{mounted && isAuthenticated && <MessagesBell />}
|
|
|
|
{/* Notifications */}
|
|
{mounted && isAuthenticated && <NotificationBell />}
|
|
{mounted && isAuthenticated && user?.subscriptionTier && (
|
|
<Badge variant="outline" className="uppercase">
|
|
{user.subscriptionTier.slug}
|
|
</Badge>
|
|
)}
|
|
|
|
{/* Auth Section */}
|
|
{!mounted ? (
|
|
// Placeholder durante SSR para evitar mismatch
|
|
<div className="w-20 h-8 animate-pulse bg-muted rounded" />
|
|
) : isLoading ? (
|
|
<div className="w-20 h-8 animate-pulse bg-muted rounded" />
|
|
) : isAuthenticated && user ? (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
|
|
<Avatar className="h-8 w-8">
|
|
<AvatarFallback>
|
|
{user.username.charAt(0).toUpperCase()}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-56">
|
|
<DropdownMenuLabel>
|
|
<div className="flex flex-col space-y-1">
|
|
<p className="text-sm font-medium leading-none">
|
|
{user.username}
|
|
</p>
|
|
{user.characterName && (
|
|
<p className="text-xs leading-none text-primary font-medium">
|
|
{user.characterName}
|
|
</p>
|
|
)}
|
|
<p className="text-xs leading-none text-muted-foreground">
|
|
{user.email}
|
|
</p>
|
|
</div>
|
|
</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem asChild>
|
|
<Link href={`/${locale}/perfil`} className="cursor-pointer">
|
|
<User className="mr-2 h-4 w-4" />
|
|
Perfil
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem
|
|
className="cursor-pointer text-destructive"
|
|
onClick={handleLogout}
|
|
>
|
|
<LogOut className="mr-2 h-4 w-4" />
|
|
Sair
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
) : (
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => setRegisterDialogOpen(true)}
|
|
size="sm"
|
|
>
|
|
Registrar
|
|
</Button>
|
|
<Button onClick={() => setLoginDialogOpen(true)} size="sm">
|
|
Entrar
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Mobile Menu */}
|
|
<div className="md:hidden">
|
|
<MobileMenu links={navLinks} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Login Dialog */}
|
|
<LoginDialog open={loginDialogOpen} onOpenChange={setLoginDialogOpen} />
|
|
|
|
{/* Register Dialog */}
|
|
<RegisterDialog open={registerDialogOpen} onOpenChange={setRegisterDialogOpen} />
|
|
</header>
|
|
);
|
|
}
|