barcha apilar ulandi
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { removeAuthToken, removeRefAuthToken } from "@/shared/lib/authCookies";
|
||||
import { cn } from "@/shared/lib/utils";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import {
|
||||
@@ -10,12 +11,14 @@ import {
|
||||
SheetTrigger,
|
||||
} from "@/shared/ui/sheet";
|
||||
import LangToggle from "@/widgets/lang-toggle/ui/lang-toggle";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
Briefcase,
|
||||
Building2,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
HelpCircle,
|
||||
LogOut,
|
||||
Menu,
|
||||
MessageSquare,
|
||||
Newspaper,
|
||||
@@ -27,6 +30,7 @@ import {
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
|
||||
type Role =
|
||||
| "superuser"
|
||||
@@ -46,13 +50,13 @@ const MENU_ITEMS = [
|
||||
label: "Foydalanuvchilar",
|
||||
icon: Users,
|
||||
path: "/user",
|
||||
roles: ["moderator", "admin", "superuser", "moderator"],
|
||||
roles: ["moderator", "admin", "superuser", "operator"],
|
||||
},
|
||||
{
|
||||
label: "Tur firmalar",
|
||||
icon: Building2,
|
||||
path: "/agencies",
|
||||
roles: ["moderator", "admin", "superuser", "moderator"],
|
||||
roles: ["moderator", "admin", "superuser", "operator"],
|
||||
},
|
||||
{
|
||||
label: "Xodimlar",
|
||||
@@ -64,20 +68,13 @@ const MENU_ITEMS = [
|
||||
label: "Bronlar",
|
||||
icon: Wallet,
|
||||
path: "/finance",
|
||||
roles: ["moderator", "admin", "superuser", "buxgalter"],
|
||||
roles: ["moderator", "admin", "superuser", "buxgalter", "tour_admin"],
|
||||
},
|
||||
{
|
||||
label: "Turlar",
|
||||
icon: Plane,
|
||||
path: "/tours",
|
||||
roles: [
|
||||
"moderator",
|
||||
"admin",
|
||||
"superuser",
|
||||
"tour_admin",
|
||||
"operator",
|
||||
"buxgalter",
|
||||
],
|
||||
roles: ["moderator", "admin", "superuser", "tour_admin"],
|
||||
children: [
|
||||
{ label: "Turlar", path: "/tours" },
|
||||
{
|
||||
@@ -87,19 +84,6 @@ const MENU_ITEMS = [
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// label: "Bronlar",
|
||||
// icon: CalendarCheck2,
|
||||
// path: "/bookings",
|
||||
// roles: [
|
||||
// "moderator",
|
||||
// "admin",
|
||||
// "superuser",
|
||||
// "tour_admin",
|
||||
// "operator",
|
||||
// "buxgalter",
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
label: "Yangiliklar",
|
||||
icon: Newspaper,
|
||||
@@ -129,7 +113,7 @@ const MENU_ITEMS = [
|
||||
{
|
||||
label: "Agentlik arizalari",
|
||||
path: "/support/tours",
|
||||
roles: ["moderator", "admin", "superuser", "operator"],
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
},
|
||||
{
|
||||
label: "Yordam arizalari",
|
||||
@@ -164,12 +148,21 @@ export function Sidebar({ role }: SidebarProps) {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const queryClient = useQueryClient();
|
||||
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
||||
|
||||
const visibleMenu = useMemo(
|
||||
() => MENU_ITEMS.filter((item) => item.roles.includes(role)),
|
||||
[role],
|
||||
);
|
||||
const visibleMenu = useMemo(() => {
|
||||
return MENU_ITEMS.filter((item) => item.roles.includes(role)).map(
|
||||
(item) => ({
|
||||
...item,
|
||||
children: item.children
|
||||
? item.children.filter(
|
||||
(child) => !child.roles || child.roles.includes(role),
|
||||
)
|
||||
: [],
|
||||
}),
|
||||
);
|
||||
}, [role]);
|
||||
|
||||
const [active, setActive] = useState<string>(location.pathname);
|
||||
const [openMenus, setOpenMenus] = useState<string[]>([]);
|
||||
@@ -190,71 +183,93 @@ export function Sidebar({ role }: SidebarProps) {
|
||||
);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
removeAuthToken();
|
||||
removeRefAuthToken();
|
||||
queryClient.clear();
|
||||
toast.success(t("Tizimdan chiqdingiz"));
|
||||
navigate("/auth/login");
|
||||
};
|
||||
|
||||
const MenuList = (
|
||||
<ul className="p-2 space-y-1">
|
||||
{visibleMenu.map(({ label, icon: Icon, path, children }) => {
|
||||
const isActive = active.startsWith(path);
|
||||
const isOpen = openMenus.includes(label);
|
||||
<div className="flex flex-col h-full justify-between">
|
||||
<ul className="p-2 space-y-1 flex-1 overflow-y-auto">
|
||||
{visibleMenu.map(({ label, icon: Icon, path, children }) => {
|
||||
const isActive = active.startsWith(path);
|
||||
const isOpen = openMenus.includes(label);
|
||||
const hasChildren = children?.length > 0;
|
||||
|
||||
return (
|
||||
<li key={path}>
|
||||
<div
|
||||
className={cn(
|
||||
"w-full flex items-center justify-between gap-2 px-2 py-3 rounded-md cursor-pointer transition text-md font-medium",
|
||||
isActive
|
||||
? "bg-gray-600 text-white"
|
||||
: "text-gray-400 hover:bg-gray-700 hover:text-white",
|
||||
)}
|
||||
onClick={() =>
|
||||
children ? toggleSubMenu(label) : handleClick(path)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon className="w-5 h-5" />
|
||||
{t(label)}
|
||||
return (
|
||||
<li key={path}>
|
||||
<div
|
||||
className={cn(
|
||||
"w-full flex items-center justify-between gap-2 px-2 py-3 rounded-md cursor-pointer transition text-md font-medium",
|
||||
isActive
|
||||
? "bg-gray-600 text-white"
|
||||
: "text-gray-400 hover:bg-gray-700 hover:text-white",
|
||||
)}
|
||||
onClick={() =>
|
||||
hasChildren ? toggleSubMenu(label) : handleClick(path)
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon className="w-5 h-5" />
|
||||
{t(label)}
|
||||
</div>
|
||||
{hasChildren && (
|
||||
<span className="transition-transform">
|
||||
{isOpen ? (
|
||||
<ChevronDown className="w-4 h-4" />
|
||||
) : (
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{children && (
|
||||
<span className="transition-transform">
|
||||
{isOpen ? (
|
||||
<ChevronDown className="w-4 h-4" />
|
||||
) : (
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
)}
|
||||
</span>
|
||||
|
||||
{hasChildren && isOpen && (
|
||||
<ul className="ml-6 mt-1 space-y-1 border-l border-gray-700 pl-3">
|
||||
{children.map((sub) => (
|
||||
<li key={sub.path}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleClick(sub.path)}
|
||||
className={cn(
|
||||
"w-full justify-start gap-2 text-sm !px-2 !py-2 cursor-pointer",
|
||||
active === sub.path
|
||||
? "bg-gray-700 text-white"
|
||||
: "text-gray-400 hover:text-white hover:bg-gray-800",
|
||||
)}
|
||||
>
|
||||
{t(sub.label)}
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
<LangToggle />
|
||||
</ul>
|
||||
|
||||
{children && isOpen && (
|
||||
<ul className="ml-6 mt-1 space-y-1 border-l border-gray-700 pl-3">
|
||||
{children.map((sub) => (
|
||||
<li key={sub.path}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleClick(sub.path)}
|
||||
className={cn(
|
||||
"w-full justify-start gap-2 text-sm !px-2 !py-2 cursor-pointer",
|
||||
active === sub.path
|
||||
? "bg-gray-700 text-white"
|
||||
: "text-gray-400 hover:text-white hover:bg-gray-800",
|
||||
)}
|
||||
>
|
||||
{t(sub.label)}
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
<LangToggle />
|
||||
</ul>
|
||||
<div className="border-t border-gray-700 mt-2 pt-3 px-2">
|
||||
<Button
|
||||
onClick={handleLogout}
|
||||
variant="ghost"
|
||||
className="w-full flex items-center justify-start gap-2 text-red-400 hover:bg-red-900/20 hover:text-red-300 mt-2"
|
||||
>
|
||||
<LogOut className="w-5 h-5" />
|
||||
<span>{t("Chiqish")}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="lg:border">
|
||||
{/* Mobil versiya */}
|
||||
<div className="lg:hidden flex items-center justify-end bg-gray-900 p-4 sticky top-0 z-50">
|
||||
<Sheet open={isSheetOpen} onOpenChange={setIsSheetOpen}>
|
||||
<div className="flex gap-4">
|
||||
@@ -277,15 +292,17 @@ export function Sidebar({ role }: SidebarProps) {
|
||||
/>
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<nav className="overflow-y-auto">{MenuList}</nav>
|
||||
<nav className="h-full">{MenuList}</nav>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</div>
|
||||
|
||||
{/* Desktop versiya */}
|
||||
<aside className="hidden bg-gray-900 lg:flex w-64 flex-col h-screen">
|
||||
<div className="flex items-center gap-2 p-4 border-b">
|
||||
<img src="/Logo_white.png" width={120} height={120} alt="logo" />
|
||||
</div>
|
||||
<nav className="flex-1 overflow-y-auto">{MenuList}</nav>
|
||||
<nav className="flex-1">{MenuList}</nav>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user