api ulandi

This commit is contained in:
Samandar Turgunboyev
2025-10-25 18:42:01 +05:00
parent 1a08775451
commit 05b752daf2
84 changed files with 11179 additions and 3724 deletions

View File

@@ -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);
};

View 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;

View File

@@ -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 royxati", 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 />