feat: revue de code, doc CODE_REVIEW, forfaits 2026, traduction LLM, providers avec modèle

Made-with: Cursor
This commit is contained in:
Sepehr Ramezani
2026-03-07 11:42:58 +01:00
parent 3d37ce4582
commit 473b3e26c7
181 changed files with 30617 additions and 7170 deletions

View File

@@ -0,0 +1,111 @@
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Languages, ChevronLeft, LogOut } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
import { Button } from '@/components/ui/button';
import { useUser } from './useUser';
import { useLogout } from './useLogout';
import { getNavItems } from './constants';
import { getInitials } from './utils';
export function DashboardSidebar() {
const pathname = usePathname();
const { data: user, isLoading } = useUser();
const { logout } = useLogout();
const navItems = getNavItems(user?.tier === 'pro');
return (
<aside className="hidden w-64 shrink-0 border-r border-border bg-card lg:flex lg:flex-col">
{/* Brand */}
<div className="flex h-14 items-center gap-2.5 px-5">
<div className="flex size-7 items-center justify-center rounded-md bg-foreground">
<Languages className="size-3.5 text-background" />
</div>
<span className="text-sm font-semibold tracking-tight text-foreground">
Office Translator
</span>
</div>
<Separator />
{/* Navigation */}
<nav className="flex flex-1 flex-col gap-1 px-3 py-4">
{navItems.map((item) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className={cn(
'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors',
isActive
? 'bg-secondary text-foreground'
: 'text-muted-foreground hover:bg-secondary/60 hover:text-foreground'
)}
>
<item.icon className="size-4 shrink-0" />
{item.label}
</Link>
);
})}
</nav>
<Separator />
{/* User section */}
{!isLoading && user && (
<div className="flex items-center gap-3 px-5 py-4">
<Avatar className="size-8">
<AvatarFallback className="bg-accent text-accent-foreground text-xs font-semibold">
{getInitials(user.name)}
</AvatarFallback>
</Avatar>
<div className="flex flex-col gap-0.5">
<span className="text-sm font-medium leading-none text-foreground">{user.name}</span>
<span className="text-xs leading-none text-muted-foreground">{user.email}</span>
</div>
<Badge
variant="secondary"
className={cn(
'ml-auto text-xs',
user.tier === 'pro' && 'border border-accent/20 bg-accent/10 text-accent'
)}
>
{user.tier === 'pro' ? 'Pro' : 'Free'}
</Badge>
</div>
)}
<Separator />
{/* Logout */}
<div className="px-3 py-3">
<Button
variant="ghost"
size="sm"
className="w-full justify-start gap-2 text-muted-foreground hover:text-foreground"
onClick={logout}
>
<LogOut className="size-3.5" />
Sign out
</Button>
</div>
{/* Back to homepage */}
<div className="px-3 py-3">
<Button variant="ghost" size="sm" className="w-full justify-start gap-2 text-muted-foreground" asChild>
<Link href="/">
<ChevronLeft className="size-3.5" />
Back to home
</Link>
</Button>
</div>
</aside>
);
}