Files
memegoat/frontend/src/components/app-sidebar.tsx
Mathis HERRIOT 0b07320974 feat: introduce new app routes with modular structure and enhanced features
Added modular app routes including `login`, `dashboard`, `categories`, `trends`, and `upload`. Introduced reusable components such as `ContentList`, `ContentSkeleton`, and `AppSidebar` for improved UI consistency. Enhanced authentication with `AuthProvider` and implemented lazy loading, dynamic layouts, and infinite scrolling for better performance.
2026-01-14 13:52:08 +01:00

244 lines
8.4 KiB
TypeScript

"use client";
import * as React from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
Home,
TrendingUp,
Clock,
LayoutGrid,
PlusCircle,
Settings,
HelpCircle,
ChevronRight,
LogOut,
User as UserIcon,
LogIn,
} from "lucide-react";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
} from "@/components/ui/sidebar";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { CategoryService } from "@/services/category.service";
import type { Category } from "@/types/content";
import { useAuth } from "@/providers/auth-provider";
const mainNav = [
{
title: "Accueil",
url: "/",
icon: Home,
},
{
title: "Tendances",
url: "/trends",
icon: TrendingUp,
},
{
title: "Nouveautés",
url: "/recent",
icon: Clock,
},
];
export function AppSidebar() {
const pathname = usePathname();
const { user, logout, isAuthenticated, isLoading } = useAuth();
const [categories, setCategories] = React.useState<Category[]>([]);
React.useEffect(() => {
CategoryService.getAll().then(setCategories).catch(console.error);
}, []);
return (
<Sidebar collapsible="icon">
<SidebarHeader className="flex items-center justify-center py-4">
<Link href="/" className="flex items-center gap-2 font-bold text-xl">
<div className="bg-primary text-primary-foreground p-1 rounded">
🐐
</div>
<span className="group-data-[collapsible=icon]:hidden">MemeGoat</span>
</Link>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarMenu>
{mainNav.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
isActive={pathname === item.url}
tooltip={item.title}
>
<Link href={item.url}>
<item.icon />
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Explorer</SidebarGroupLabel>
<SidebarMenu>
<Collapsible asChild className="group/collapsible">
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton tooltip="Catégories">
<LayoutGrid />
<span>Catégories</span>
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{categories.map((category) => (
<SidebarMenuSubItem key={category.id}>
<SidebarMenuSubButton asChild isActive={pathname === `/category/${category.slug}`}>
<Link href={`/category/${category.slug}`}>
<span>{category.name}</span>
</Link>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
</SidebarMenu>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Communauté</SidebarGroupLabel>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild tooltip="Publier">
<Link href="/upload">
<PlusCircle />
<span>Publier</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarMenu>
{isAuthenticated && user ? (
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
>
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={user.avatarUrl} alt={user.username} />
<AvatarFallback className="rounded-lg">
{user.username.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight group-data-[collapsible=icon]:hidden">
<span className="truncate font-semibold">
{user.displayName || user.username}
</span>
<span className="truncate text-xs">{user.email}</span>
</div>
<ChevronRight className="ml-auto size-4 group-data-[collapsible=icon]:hidden" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
side="right"
align="end"
sideOffset={4}
>
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={user.avatarUrl} alt={user.username} />
<AvatarFallback className="rounded-lg">
{user.username.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">
{user.displayName || user.username}
</span>
<span className="truncate text-xs">{user.email}</span>
</div>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem asChild>
<Link href="/profile" className="flex items-center gap-2">
<UserIcon className="size-4" />
<span>Profil</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/settings" className="flex items-center gap-2">
<Settings className="size-4" />
<span>Paramètres</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => logout()}>
<LogOut className="size-4 mr-2" />
<span>Déconnexion</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
) : (
<SidebarMenuItem>
<SidebarMenuButton asChild tooltip="Se connecter">
<Link href="/login">
<LogIn className="size-4" />
<span>Se connecter</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
)}
<SidebarMenuItem>
<SidebarMenuButton asChild tooltip="Aide">
<Link href="/help">
<HelpCircle />
<span>Aide</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
);
}