api ulandi
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import httpClient from "@/shared/config/api/httpClient";
|
||||
import { LanguageRoutes } from "@/shared/config/i18n/type";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import {
|
||||
@@ -7,12 +8,16 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/shared/ui/dropdown-menu";
|
||||
import { languages } from "@/widgets/lang-toggle/lib/data";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { GlobeIcon } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const LangToggle = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const changeLanguage = (lng: LanguageRoutes) => {
|
||||
httpClient.defaults.headers.common["Accept-Language"] = lng;
|
||||
queryClient.refetchQueries();
|
||||
i18n.changeLanguage(lng);
|
||||
};
|
||||
|
||||
|
||||
109
src/widgets/real-pagination/ui/RealPagination.tsx
Normal file
109
src/widgets/real-pagination/ui/RealPagination.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
"use client";
|
||||
|
||||
import type { Table } from "@tanstack/react-table";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
interface Props<T> {
|
||||
table: Table<T>;
|
||||
totalPages?: number;
|
||||
namePage?: string;
|
||||
namePageSize?: string;
|
||||
}
|
||||
|
||||
const RealPagination = <T,>({
|
||||
table,
|
||||
totalPages = 1,
|
||||
namePage,
|
||||
namePageSize,
|
||||
}: Props<T>) => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const currentPage = table.getState().pagination.pageIndex + 1;
|
||||
|
||||
const updateUrl = useCallback(
|
||||
(page: number, pageSize: number) => {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
newParams.set(namePage ? namePage : "page", page.toString());
|
||||
newParams.set(
|
||||
namePageSize ? namePageSize : "pageSize",
|
||||
pageSize.toString(),
|
||||
);
|
||||
setSearchParams(newParams);
|
||||
},
|
||||
[searchParams, setSearchParams],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const urlPage = parseInt(searchParams.get("page") || "1", 10);
|
||||
const urlPageSize = parseInt(searchParams.get("pageSize") || "10", 10);
|
||||
|
||||
if (urlPage - 1 !== table.getState().pagination.pageIndex) {
|
||||
table.setPageIndex(urlPage - 1);
|
||||
}
|
||||
if (urlPageSize !== table.getState().pagination.pageSize) {
|
||||
table.setPageSize(urlPageSize);
|
||||
}
|
||||
}, [searchParams, table]);
|
||||
|
||||
const handlePrev = () => {
|
||||
if (currentPage > 1) {
|
||||
table.setPageIndex(currentPage - 2);
|
||||
updateUrl(currentPage - 1, table.getState().pagination.pageSize);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
if (currentPage < totalPages) {
|
||||
table.setPageIndex(currentPage);
|
||||
updateUrl(currentPage + 1, table.getState().pagination.pageSize);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageClick = (page: number) => {
|
||||
table.setPageIndex(page - 1);
|
||||
updateUrl(page, table.getState().pagination.pageSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
{/* Previous Button */}
|
||||
<button
|
||||
disabled={currentPage === 1}
|
||||
onClick={handlePrev}
|
||||
className="p-2 rounded-lg border border-slate-600 text-slate-300 hover:bg-slate-700/50
|
||||
disabled:opacity-50 disabled:cursor-not-allowed transition-all hover:border-slate-500"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
{/* Page Numbers */}
|
||||
{[...Array(totalPages)].map((_, i) => (
|
||||
<button
|
||||
key={i}
|
||||
onClick={() => handlePageClick(i + 1)}
|
||||
className={`px-4 py-2 rounded-lg border transition-all font-medium ${
|
||||
currentPage === i + 1
|
||||
? "bg-gradient-to-r from-blue-600 to-cyan-600 border-blue-500 text-white shadow-lg shadow-cyan-500/50"
|
||||
: "border-slate-600 text-slate-300 hover:bg-slate-700/50 hover:border-slate-500"
|
||||
}`}
|
||||
>
|
||||
{i + 1}
|
||||
</button>
|
||||
))}
|
||||
|
||||
{/* Next Button */}
|
||||
<button
|
||||
disabled={currentPage === totalPages}
|
||||
onClick={handleNext}
|
||||
className="p-2 rounded-lg border border-slate-600 text-slate-300 hover:bg-slate-700/50
|
||||
disabled:opacity-50 disabled:cursor-not-allowed transition-all hover:border-slate-500"
|
||||
>
|
||||
<ChevronRight className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RealPagination;
|
||||
@@ -13,7 +13,6 @@ import LangToggle from "@/widgets/lang-toggle/ui/lang-toggle";
|
||||
import {
|
||||
Briefcase,
|
||||
Building2,
|
||||
CalendarCheck2,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
HelpCircle,
|
||||
@@ -29,44 +28,83 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
type Role = "admin" | "manager" | "user";
|
||||
type Role =
|
||||
| "superuser"
|
||||
| "admin"
|
||||
| "moderator"
|
||||
| "tour_admin"
|
||||
| "buxgalter"
|
||||
| "operator"
|
||||
| "user";
|
||||
|
||||
interface SidebarProps {
|
||||
role: Role;
|
||||
}
|
||||
|
||||
/** --- MENYU TUZILMASI --- **/
|
||||
const MENU_ITEMS = [
|
||||
{ label: "Foydalanuvchilar", icon: Users, path: "/user", roles: ["admin"] },
|
||||
{
|
||||
label: "Foydalanuvchilar",
|
||||
icon: Users,
|
||||
path: "/user",
|
||||
roles: ["moderator", "admin", "superuser", "moderator"],
|
||||
},
|
||||
{
|
||||
label: "Tur firmalar",
|
||||
icon: Building2,
|
||||
path: "/agencies",
|
||||
roles: ["admin", "manager"],
|
||||
roles: ["moderator", "admin", "superuser", "moderator"],
|
||||
},
|
||||
{
|
||||
label: "Xodimlar",
|
||||
icon: Briefcase,
|
||||
path: "/employees",
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
},
|
||||
{
|
||||
label: "Bronlar",
|
||||
icon: Wallet,
|
||||
path: "/finance",
|
||||
roles: ["moderator", "admin", "superuser", "buxgalter"],
|
||||
},
|
||||
{ label: "Xodimlar", icon: Briefcase, path: "/employees", roles: ["admin"] },
|
||||
{ label: "Byudjet", icon: Wallet, path: "/finance", roles: ["admin"] },
|
||||
{
|
||||
label: "Turlar",
|
||||
icon: Plane,
|
||||
path: "/tours",
|
||||
roles: ["admin", "manager"],
|
||||
roles: [
|
||||
"moderator",
|
||||
"admin",
|
||||
"superuser",
|
||||
"tour_admin",
|
||||
"operator",
|
||||
"buxgalter",
|
||||
],
|
||||
children: [
|
||||
{ label: "Turlar", path: "/tours" },
|
||||
{ label: "Tur sozlamalari", path: "/tours/setting" },
|
||||
{
|
||||
label: "Tur sozlamalari",
|
||||
path: "/tours/setting",
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Bronlar",
|
||||
icon: CalendarCheck2,
|
||||
path: "/bookings",
|
||||
roles: ["admin", "manager", "user"],
|
||||
},
|
||||
// {
|
||||
// label: "Bronlar",
|
||||
// icon: CalendarCheck2,
|
||||
// path: "/bookings",
|
||||
// roles: [
|
||||
// "moderator",
|
||||
// "admin",
|
||||
// "superuser",
|
||||
// "tour_admin",
|
||||
// "operator",
|
||||
// "buxgalter",
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
label: "Yangiliklar",
|
||||
icon: Newspaper,
|
||||
path: "/news",
|
||||
roles: ["admin", "manager"],
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
children: [
|
||||
{ label: "Yangiliklar", path: "/news" },
|
||||
{ label: "Kategoriya", path: "/news/categories" },
|
||||
@@ -76,7 +114,7 @@ const MENU_ITEMS = [
|
||||
label: "FAQ",
|
||||
icon: MessageSquare,
|
||||
path: "/faq",
|
||||
roles: ["admin"],
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
children: [
|
||||
{ label: "Savollar ro‘yxati", path: "/faq" },
|
||||
{ label: "Savollar kategoriyasi", path: "/faq/categories" },
|
||||
@@ -86,17 +124,32 @@ const MENU_ITEMS = [
|
||||
label: "Arizalar",
|
||||
icon: HelpCircle,
|
||||
path: "/support",
|
||||
roles: ["admin", "manager"],
|
||||
roles: ["moderator", "admin", "superuser", "tour_admin", "operator"],
|
||||
children: [
|
||||
{ label: "Agentlik arizalari", path: "/support/tours", roles: ["admin"] },
|
||||
{ label: "Yordam arizalari", path: "/support/user", roles: ["admin"] },
|
||||
{
|
||||
label: "Agentlik arizalari",
|
||||
path: "/support/tours",
|
||||
roles: ["moderator", "admin", "superuser", "operator"],
|
||||
},
|
||||
{
|
||||
label: "Yordam arizalari",
|
||||
path: "/support/user",
|
||||
roles: [
|
||||
"moderator",
|
||||
"admin",
|
||||
"superuser",
|
||||
"tour_admin",
|
||||
"operator",
|
||||
"buxgalter",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Tur sozlamalari",
|
||||
label: "Sayt sozlamalari",
|
||||
icon: Settings,
|
||||
path: "/tour-settings",
|
||||
roles: ["admin"],
|
||||
roles: ["moderator", "admin", "superuser"],
|
||||
children: [
|
||||
{ label: "Sayt SEOsi", path: "/site-seo/" },
|
||||
{ label: "Offerta", path: "/site-pages/" },
|
||||
@@ -201,7 +254,7 @@ export function Sidebar({ role }: SidebarProps) {
|
||||
|
||||
return (
|
||||
<div className="lg:border">
|
||||
<div className="lg:hidden flex items-center justify-between bg-gray-900 p-4 sticky top-0 z-50">
|
||||
<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">
|
||||
<LangToggle />
|
||||
|
||||
Reference in New Issue
Block a user