Files
next-go-blog/components/header/header.tsx
Beyhan Oğur 6d95e27114 first commit
2026-04-26 22:16:43 +03:00

173 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import Link from "next/link";
import { useTheme } from "next-themes";
import { useAppSelector, useAppDispatch } from "@/lib/hooks";
import { logout } from "@/lib/features/auth/authSlice";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Sun, Moon, LogOut, User, LayoutDashboard, Menu } from "lucide-react";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { useState, useEffect } from "react";
import { getAvatarUrl } from "@/lib/utils";
export function Header() {
const { setTheme, theme } = useTheme();
const dispatch = useAppDispatch();
const { isAuthenticated, user } = useAppSelector((state) => state.auth);
const [mounted, setMounted] = useState(false);
// Prevent hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
const handleLogout = () => {
dispatch(logout());
};
if (!mounted) {
return (
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-14 items-center pl-10 pr-10">
<div className="mr-4 hidden md:flex">
<Link href="/" className="mr-6 flex items-center space-x-2">
<span className="hidden font-bold sm:inline-block">
NextGoBlog
</span>
</Link>
<nav className="flex items-center space-x-6 text-sm font-medium">
<Link href="/blog">Blog</Link>
<Link href="/about">Hakkında</Link>
</nav>
</div>
<div className="flex flex-1 items-center justify-end space-x-2">
<div className="flex items-center gap-2">
<Button variant="ghost" asChild>
<Link href="/login">Giriş Yap</Link>
</Button>
<Button asChild>
<Link href="/register">Kayıt Ol</Link>
</Button>
</div>
</div>
</div>
</header>
)
}
return (
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-14 items-center pl-10 pr-10">
{/* Desktop Interface */}
<div className="mr-4 hidden md:flex">
<Link href="/" className="mr-6 flex items-center space-x-2">
<span className="hidden font-bold sm:inline-block">
NextGoBlog
</span>
</Link>
<nav className="flex items-center space-x-6 text-sm font-medium">
<Link href="/blog">Blog</Link>
<Link href="/about">Hakkında</Link>
</nav>
</div>
{/* Mobile Interface */}
<Sheet>
<SheetTrigger asChild>
<Button
variant="ghost"
className="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
>
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle Menu</span>
</Button>
</SheetTrigger>
<SheetContent side="left" className="pr-0">
<Link href="/" className="flex items-center">
<span className="font-bold">NextGoBlog</span>
</Link>
<nav className="mt-8 flex flex-col gap-4">
<Link href="/blog">Blog</Link>
<Link href="/about">Hakkında</Link>
</nav>
</SheetContent>
</Sheet>
{/* Right Side */}
<div className="flex flex-1 items-center justify-end space-x-2">
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
>
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
{isAuthenticated ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
<Avatar className="h-8 w-8">
<AvatarImage src={getAvatarUrl(user?.avatar_url)} alt={user?.username} />
<AvatarFallback>{user?.username?.slice(0, 2).toUpperCase()}</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end" forceMount>
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
<p className="text-sm font-medium leading-none">{user?.username}</p>
<p className="text-xs leading-none text-muted-foreground">
{user?.email}
</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
{user?.roles?.some((r: any) => r.name === "admin") && (
<DropdownMenuItem asChild>
<Link href="/admin">
<LayoutDashboard className="mr-2 h-4 w-4" />
<span>Admin Panel</span>
</Link>
</DropdownMenuItem>
)}
<DropdownMenuItem asChild>
<Link href="/profile">
<User className="mr-2 h-4 w-4" />
<span>Profil</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleLogout}>
<LogOut className="mr-2 h-4 w-4" />
<span>Çıkış Yap</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
) : (
<div className="flex items-center gap-2">
<Button variant="ghost" asChild>
<Link href="/login">Giriş Yap</Link>
</Button>
<Button asChild>
<Link href="/register">Kayıt Ol</Link>
</Button>
</div>
)}
</div>
</div>
</header>
);
}