90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
"use client";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import {
|
|
LayoutGrid, Package, QrCode, ShieldCheck, BarChart3, Settings,
|
|
ShieldHalf, LogOut, CreditCard,
|
|
} from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { clearToken } from "@/lib/api";
|
|
import { useLanguage } from "@/contexts/LanguageContext";
|
|
|
|
|
|
export default function Sidebar({ org, open = false, onClose }: { org?: any; open?: boolean; onClose?: () => void }) {
|
|
const path = usePathname();
|
|
const { t } = useLanguage();
|
|
const nav = [
|
|
{ href: "/dashboard", label: t.dashboard, icon: LayoutGrid },
|
|
{ href: "/dashboard/products", label: t.products, icon: Package },
|
|
{ href: "/dashboard/qr", label: t.qr_management, icon: QrCode },
|
|
{ href: "/dashboard/compliance", label: t.compliance, icon: ShieldCheck },
|
|
{ href: "/dashboard/analytics", label: t.analytics, icon: BarChart3 },
|
|
{ href: "/dashboard/billing", label: t.billing, icon: CreditCard },
|
|
{ href: "/dashboard/settings", label: t.settings_menu, icon: Settings },
|
|
];
|
|
function onLogout() {
|
|
clearToken();
|
|
window.location.href = "/login";
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{open && <div className="fixed inset-0 bg-black/40 z-30 md:hidden" onClick={onClose} />}
|
|
<aside className={`w-64 shrink-0 bg-sidebar text-white flex flex-col h-screen z-40
|
|
fixed inset-y-0 left-0 transition-transform md:sticky md:top-0 md:translate-x-0
|
|
${open ? "translate-x-0" : "-translate-x-full"}`}>
|
|
<div className="px-6 py-6 flex items-center gap-3">
|
|
<div className="h-10 w-10 rounded-xl bg-white/10 grid place-items-center">
|
|
<ShieldHalf className="h-6 w-6 text-white" />
|
|
</div>
|
|
<div>
|
|
<div className="font-extrabold text-lg leading-none">VerifyPack</div>
|
|
<div className="text-[10px] text-white/50 mt-1">{t.tagline}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<nav className="flex-1 overflow-y-auto px-3 space-y-1 mt-2">
|
|
{nav.map(({ href, label, icon: Icon }) => {
|
|
const active = path === href;
|
|
return (
|
|
<Link key={href} href={href}
|
|
className={cn(
|
|
"flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition",
|
|
active ? "bg-brand-500 text-white shadow"
|
|
: "text-white/70 hover:bg-white/10 hover:text-white"
|
|
)}>
|
|
<Icon className="h-[18px] w-[18px]" />
|
|
{label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="p-4 space-y-3 shrink-0 border-t border-white/5">
|
|
{org ? (
|
|
<>
|
|
<div className="rounded-xl bg-white/5 px-4 py-3">
|
|
<div className="text-sm font-semibold">{org.name}</div>
|
|
<div className="text-[11px] text-white/50">{t.org_id_label}: {org.slug}</div>
|
|
</div>
|
|
<div className="rounded-xl bg-white/5 px-4 py-3 text-[11px] text-white/70 space-y-1">
|
|
<div className="text-white font-semibold">Plan: {org.plan?.name ?? "Free"}</div>
|
|
<div>{t.products}: {org.product_count} / {org.plan?.product_limit ?? "∞"}</div>
|
|
<div>{t.users}: {org.user_count} / {org.plan?.user_limit ?? "∞"}</div>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<div className="rounded-xl bg-white/5 px-4 py-3 text-[11px] text-white/50">
|
|
No organization yet
|
|
</div>
|
|
)}
|
|
<button onClick={onLogout}
|
|
className="w-full flex items-center gap-2 px-3 py-2.5 rounded-xl text-sm font-medium text-white/70 hover:bg-white/10 hover:text-white">
|
|
<LogOut className="h-[18px] w-[18px]" /> {t.logout}
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
</>
|
|
);
|
|
}
|