This commit is contained in:
Samandar Turgunboyev
2025-12-01 13:23:40 +05:00
parent 5c4e1327be
commit d4788c7cb2
15 changed files with 270 additions and 142 deletions

View File

@@ -69,7 +69,7 @@ export function DataTableDistruct<TData, TValue>({
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. Tuman mavjud emas
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@@ -191,12 +191,8 @@ export default function District() {
return ( return (
<DashboardLayout> <DashboardLayout>
<div className="space-y-6"> <>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-foreground">Tumanlar</h1>
<p className="text-muted-foreground mt-1">Tumanlarni boshqarish</p>
</div>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<AddedButton onClick={() => form.reset({ name: "" })} /> <AddedButton onClick={() => form.reset({ name: "" })} />
@@ -260,7 +256,7 @@ export default function District() {
</Dialog> </Dialog>
</div> </div>
<div className="space-y-6 mt-5"> <div className="space-y-6">
<h1 className="text-3xl font-bold">Tumanlar royxati</h1> <h1 className="text-3xl font-bold">Tumanlar royxati</h1>
{/* Loading state */} {/* Loading state */}
@@ -282,7 +278,7 @@ export default function District() {
<p className="text-gray-500">Tumanlar mavjud emas</p> <p className="text-gray-500">Tumanlar mavjud emas</p>
)} )}
</div> </div>
</div> </>
<Dialog open={deleteDialog} onOpenChange={setDeleteDialog}> <Dialog open={deleteDialog} onOpenChange={setDeleteDialog}>
<DialogContent> <DialogContent>

View File

@@ -69,7 +69,7 @@ export function DataTable<TData, TValue>({
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. Shifokor mavjud emas
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@@ -4,16 +4,18 @@ import { useMutation } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import clsx from "clsx"; import clsx from "clsx";
import { import {
Banknote,
Calendar, Calendar,
Clipboard,
FileText, FileText,
HomeIcon,
Layers,
List, List,
MapPin, Loader2,
Syringe, MapPinCheck,
MapPinHouse,
MapPinned,
Pill,
User, User,
} from "lucide-react"; } from "lucide-react";
import { useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -31,7 +33,7 @@ const navItems: NavItem[] = [
id: "lokatsiya", id: "lokatsiya",
title: "Lokatsiya jo'natish", title: "Lokatsiya jo'natish",
link: "/location", link: "/location",
icon: <MapPin className="w-8 h-8" />, icon: <MapPinCheck className="w-8 h-8" />,
description: "Manzilni jo'natish", description: "Manzilni jo'natish",
featured: true, featured: true,
}, },
@@ -56,12 +58,14 @@ const navItems: NavItem[] = [
export default function Home() { export default function Home() {
const featuredItems = navItems.filter((item) => item.featured); const featuredItems = navItems.filter((item) => item.featured);
const router = useNavigate(); const router = useNavigate();
const [locationLoad, setLocationLoad] = useState<boolean>(false);
const { mutate } = useMutation({ const { mutate } = useMutation({
mutationFn: (body: SendLocation) => location_api.send_loaction(body), mutationFn: (body: SendLocation) => location_api.send_loaction(body),
onSuccess: () => { onSuccess: () => {
toast.success("Lokatsiya jo'natildi"); toast.success("Lokatsiya jo'natildi");
router("/location"); router("/location");
setLocationLoad(false);
}, },
onError: (error: AxiosError) => { onError: (error: AxiosError) => {
const data = error.response?.data as { message?: string }; const data = error.response?.data as { message?: string };
@@ -77,6 +81,7 @@ export default function Home() {
name: string[]; name: string[];
}; };
}; };
setLocationLoad(false);
const message = const message =
Array.isArray(errorName.data?.name) && errorName.data.name.length Array.isArray(errorName.data?.name) && errorName.data.name.length
@@ -92,6 +97,7 @@ export default function Home() {
}); });
const handleLocationClick = () => { const handleLocationClick = () => {
setLocationLoad(true);
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
(pos) => { (pos) => {
mutate({ mutate({
@@ -125,41 +131,48 @@ export default function Home() {
<div className="px-4 sm:px-6 mt-5 lg:px-4 bg-background"> <div className="px-4 sm:px-6 mt-5 lg:px-4 bg-background">
<div className="max-w-6xl mx-auto"> <div className="max-w-6xl mx-auto">
<p className="text-md font-bold text-black mb-5 uppercase">Asosiy</p> <p className="text-md font-bold text-black mb-5 uppercase">Asosiy</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-5"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{featuredItems.map((item) => { {featuredItems.map((item) => {
const isLocation = item.id === "lokatsiya"; const isLocation = item.id === "lokatsiya";
const specification = item.id === "spetsifikatsiya";
const tourPlan = item.id === "tour_plan";
return ( return (
<div <div
key={item.id} key={item.id}
onClick={isLocation ? handleLocationClick : undefined} onClick={isLocation ? handleLocationClick : undefined}
className="group relative px-4 cursor-pointer" className="group relative cursor-pointer flex justify-start"
> >
{!isLocation ? ( {!isLocation ? (
<Link to={item.link} className="absolute inset-0"></Link> <Link
to={item.link}
className="absolute inset-0 z-50"
></Link>
) : null} ) : null}
<div <div
className={clsx( className={clsx(
"flex items-start gap-6 pb-2 border-b border-border hover:border-primary/30 transition-colors", "flex rounded-xl shadow-sm items-start gap-2 border-b p-2 pb-2 border-border hover:border-primary/30 transition-colors",
isLocation && "shadow-sm p-2 rounded-xl scale-[115%]", isLocation
? "w-full"
: specification
? "w-[95%]"
: tourPlan && "w-[85%]",
)} )}
> >
<div <div
className={clsx( className={clsx(
"shrink-0 w-12 h-12 rounded-lg text-primary flex items-center justify-center", "shrink-0 w-12 h-12 rounded-lg flex items-center justify-center bg-primary text-white",
isLocation && "bg-primary text-white",
)} )}
> >
{item.icon} {isLocation && locationLoad ? (
<Loader2 className="animate-spin" />
) : (
item.icon
)}
</div> </div>
<div className="flex-1"> <div className="flex-1">
<h3 <h3 className={clsx("text-lg font-bold text-primary")}>
className={clsx(
"text-lg font-bold text-foreground",
isLocation && "text-primary",
)}
>
{item.title} {item.title}
</h3> </h3>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
@@ -210,7 +223,7 @@ export default function Home() {
<Link to={"/district"} className="border border-border rounded-lg"> <Link to={"/district"} className="border border-border rounded-lg">
<div className="flex flex-col items-center text-center p-4"> <div className="flex flex-col items-center text-center p-4">
<div className="text-primary/60 group-hover:text-primary transition-colors mb-3"> <div className="text-primary/60 group-hover:text-primary transition-colors mb-3">
<Layers className="w-6 h-6" /> <MapPinned className="w-6 h-6" />
</div> </div>
<h4 className="font-semibold text-foreground text-sm">Tuman</h4> <h4 className="font-semibold text-foreground text-sm">Tuman</h4>
</div> </div>
@@ -218,7 +231,7 @@ export default function Home() {
<Link to={"/object"} className="border border-border rounded-lg"> <Link to={"/object"} className="border border-border rounded-lg">
<div className="flex flex-col items-center text-center p-4"> <div className="flex flex-col items-center text-center p-4">
<div className="text-primary/60 group-hover:text-primary transition-colors mb-3"> <div className="text-primary/60 group-hover:text-primary transition-colors mb-3">
<HomeIcon className="w-6 h-6" /> <MapPinHouse className="w-6 h-6" />
</div> </div>
<h4 className="font-semibold text-foreground text-sm"> <h4 className="font-semibold text-foreground text-sm">
Obyekt Obyekt
@@ -242,7 +255,7 @@ export default function Home() {
<Link to={"/pharmacy"} className="border border-border rounded-lg"> <Link to={"/pharmacy"} className="border border-border rounded-lg">
<div className="flex flex-col items-center text-center p-4"> <div className="flex flex-col items-center text-center p-4">
<div className="text-primary/60 group-hover:text-primary transition-colors mb-3"> <div className="text-primary/60 group-hover:text-primary transition-colors mb-3">
<Syringe className="w-6 h-6" /> <Pill className="w-6 h-6" />
</div> </div>
<h4 className="font-semibold text-foreground text-sm"> <h4 className="font-semibold text-foreground text-sm">
Dorixona Dorixona
@@ -257,10 +270,10 @@ export default function Home() {
> >
<div className="flex flex-col items-center text-center p-4"> <div className="flex flex-col items-center text-center p-4">
<div className="text-primary/60 group-hover:text-primary transition-colors mb-3"> <div className="text-primary/60 group-hover:text-primary transition-colors mb-3">
<Clipboard className="w-14 h-14" /> <Banknote className="w-14 h-14" />
</div> </div>
<h4 className="font-semibold text-foreground text-lg"> <h4 className="font-semibold text-foreground text-lg">
Hisobotlar To'lovlar
</h4> </h4>
</div> </div>
</Link> </Link>

View File

@@ -346,7 +346,7 @@ const MyLocation: React.FC = () => {
colSpan={columns.length} colSpan={columns.length}
className="h-24 text-center" className="h-24 text-center"
> >
No results. Hech qanday lokatsiya jo'natilmagan
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@@ -69,7 +69,7 @@ export function DataTableObject<ObjectAllData, TValue>({
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. Obyekt mavjud emas
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@@ -9,6 +9,7 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from "@/shared/ui/dialog"; } from "@/shared/ui/dialog";
import { Skeleton } from "@/shared/ui/skeleton";
import { DashboardLayout } from "@/widgets/dashboard-layout/ui/DashboardLayout"; import { DashboardLayout } from "@/widgets/dashboard-layout/ui/DashboardLayout";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { useState } from "react"; import { useState } from "react";
@@ -80,16 +81,22 @@ const ObjectList = () => {
</div> </div>
)} )}
{!isLoading && !isError && objects && objects.length > 0 && ( {isLoading ? (
<div className="space-y-3">
{[1, 2, 3].map((i) => (
<Skeleton key={i} className="h-12 w-full rounded-md" />
))}
</div>
) : isError ? (
<p className="text-red-500">
Tumanlar yuklanmadi. Qayta urinib koring.
</p>
) : objects ? (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<DataTableObject columns={columns} data={objects} /> <DataTableObject columns={columns} data={objects} />
</div> </div>
)} ) : (
<p className="text-gray-500">Tumanlar mavjud emas</p>
{!isLoading && !isError && objects && objects.length === 0 && (
<div className="flex justify-center items-center h-64">
<span className="text-gray-500">Hech qanday obyekt topilmadi.</span>
</div>
)} )}
</div> </div>

View File

@@ -46,8 +46,8 @@ const PharmacyList = () => {
)} )}
{!isLoading && !isError && data?.length === 0 && ( {!isLoading && !isError && data?.length === 0 && (
<div className="flex justify-center items-center py-20"> <div className="h-[80vh] flex justify-center items-center w-[90%] fixed">
<p className="text-gray-500">Hech qanday dorixona topilmadi</p> <p>Dorixona mavjud emas</p>
</div> </div>
)} )}

View File

@@ -92,10 +92,10 @@ const PlanTour = () => {
<DashboardLayout> <DashboardLayout>
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
<h1 className="text-4xl font-bold text-gray-900 mb-2"> <h1 className="text-4xl font-bold text-gray-900 mb-2">
Oylik hisobotlar Oylik to'lovlar
</h1> </h1>
<p className="text-gray-600"> <p className="text-gray-600">
Dorixonalar uchun oylik summalarni boshqaring Dorixonalar uchun oylik to'lovlarni boshqaring
</p> </p>
{isLoading && ( {isLoading && (
@@ -110,6 +110,12 @@ const PlanTour = () => {
</div> </div>
)} )}
{!isLoading && !isError && data && data.length === 0 ? (
<div className="h-[80vh] flex justify-center items-center w-[90%] fixed">
<p>Hech qanday to'lovlar yo'q</p>
</div>
) : (
<>
<Card className="mb-4 border-0 p-0 mt-5"> <Card className="mb-4 border-0 p-0 mt-5">
<CardHeader className="bg-blue-500 p-3 text-white"> <CardHeader className="bg-blue-500 p-3 text-white">
<CardTitle className="flex items-center gap-2 justify-center"> <CardTitle className="flex items-center gap-2 justify-center">
@@ -144,6 +150,8 @@ const PlanTour = () => {
</Card> </Card>
<PlanPrice selectedMonth={selectedMonth} pharmacies={pharmacies} /> <PlanPrice selectedMonth={selectedMonth} pharmacies={pharmacies} />
</>
)}
</div> </div>
</DashboardLayout> </DashboardLayout>
); );

View File

@@ -125,9 +125,9 @@ export function HistoryListPage() {
</div> </div>
)) ))
) : ( ) : (
<p className="text-center text-gray-500 py-10"> <div className="fixed h-[70vh] flex justify-center items-center w-full">
{"Hozircha ma'lumot yoq."} <p className="text-gray-500">{"Hozircha ma'lumot yoq."}</p>
</p> </div>
)} )}
</div> </div>
</div> </div>

View File

@@ -65,7 +65,7 @@ export function DataTable({ columns, data }: DataTableProps<TourItemData>) {
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. Bu oy uchun tur plan mavjud emas
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@@ -18,7 +18,7 @@ const rippleVariants = {
const AddedButton: React.FC<AddedButtonProps> = ({ onClick }) => { const AddedButton: React.FC<AddedButtonProps> = ({ onClick }) => {
return ( return (
<div className="fixed bottom-8 right-8 flex items-center justify-center w-16 h-16"> <div className="fixed bottom-8 right-8 flex items-center justify-center w-16 h-16 z-50">
{[0.5, 1, 1.5].map((delay, i) => ( {[0.5, 1, 1.5].map((delay, i) => (
<motion.span <motion.span
key={i} key={i}

View File

@@ -1,8 +1,8 @@
"use client"; "use client";
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog"; import * as SheetPrimitive from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react"; import { XIcon } from "lucide-react";
import * as React from "react";
import { cn } from "@/shared/lib/utils"; import { cn } from "@/shared/lib/utils";
@@ -47,6 +47,7 @@ function SheetOverlay({
function SheetContent({ function SheetContent({
className, className,
children, children,
closedButton,
side = "right", side = "right",
...props ...props
}: React.ComponentProps<typeof SheetPrimitive.Content> & { }: React.ComponentProps<typeof SheetPrimitive.Content> & {
@@ -72,10 +73,12 @@ function SheetContent({
{...props} {...props}
> >
{children} {children}
{closedButton && (
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none"> <SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
<XIcon className="size-4" /> <XIcon className="size-4" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</SheetPrimitive.Close> </SheetPrimitive.Close>
)}
</SheetPrimitive.Content> </SheetPrimitive.Content>
</SheetPortal> </SheetPortal>
); );
@@ -129,11 +132,11 @@ function SheetDescription({
export { export {
Sheet, Sheet,
SheetTrigger,
SheetClose, SheetClose,
SheetContent, SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription, SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
}; };

View File

@@ -1,22 +1,30 @@
import Logo from "@/assets/logo.png"; import Logo from "@/assets/logo.png";
import { location_api, type SendLocation } from "@/features/home/lib/api";
import { cn } from "@/shared/lib/utils"; import { cn } from "@/shared/lib/utils";
import { Button } from "@/shared/ui/button"; import { Button } from "@/shared/ui/button";
import { Sheet, SheetContent } from "@/shared/ui/sheet"; import { Sheet, SheetClose, SheetContent } from "@/shared/ui/sheet";
import { useMutation } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { import {
Building, Banknote,
Building2,
Calendar, Calendar,
ChevronLeft, ChevronLeft,
FileText, FileText,
MapPin, Home,
List,
Loader2,
MapPinCheck,
MapPinHouse,
MapPinned,
Menu, Menu,
Navigation, Pill,
Truck,
User, User,
X,
} from "lucide-react"; } from "lucide-react";
import { useState, type ReactNode } from "react"; import { useState, type ReactNode } from "react";
import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import { toast } from "sonner";
interface NavItem { interface NavItem {
title: string; title: string;
@@ -25,24 +33,63 @@ interface NavItem {
} }
const navItems: NavItem[] = [ const navItems: NavItem[] = [
{ title: "Reja", href: "/plan", icon: Calendar }, { title: "Asosiy sahifa", href: "/", icon: Home },
{ title: "Tuman", href: "/district", icon: MapPin }, { title: "Lokatsiya jo'natish", href: "/location", icon: MapPinCheck },
{ title: "Obyekt", href: "/object", icon: Building2 },
{ title: "Shifokor", href: "/physician", icon: User },
{ title: "Dorixona", href: "/pharmacy", icon: Building },
{ title: "Tur Plan", href: "/type-plan", icon: Truck },
{ title: "Lokatsiya", href: "/location", icon: Navigation },
{ title: "Spetsifikatsiya", href: "/specification", icon: FileText }, { title: "Spetsifikatsiya", href: "/specification", icon: FileText },
{ title: "Tur Plan", href: "/tour-plan", icon: List },
{ title: "Reja", href: "/plan", icon: Calendar },
{ title: "Tuman", href: "/district", icon: MapPinned },
{ title: "Obyekt", href: "/object", icon: MapPinHouse },
{ title: "Shifokor", href: "/physician", icon: User },
{ title: "Dorixona", href: "/pharmacy", icon: Pill },
{ title: "To'lovlar", href: "/type-plan", icon: Banknote },
]; ];
export function DashboardLayout({ children }: { children: ReactNode }) { export function DashboardLayout({ children }: { children: ReactNode }) {
const location = useLocation(); const location = useLocation();
const pathname = location.pathname; const pathname = location.pathname;
const router = useNavigate(); const router = useNavigate();
const params = useParams();
const locale = params.locale as string;
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const [locationLoad, setLocationLoad] = useState(false);
const { mutate: sendLocation } = useMutation({
mutationFn: (body: SendLocation) => location_api.send_loaction(body),
onSuccess: () => {
toast.success("Lokatsiya jo'natildi");
setLocationLoad(false);
router("/location");
},
onError: (error: AxiosError) => {
const data = error.response?.data as { message?: string };
toast.error(data?.message || "Xatolik yuz berdi");
setLocationLoad(false);
},
});
const handleSidebarLocationClick = () => {
setLocationLoad(true);
navigator.geolocation.getCurrentPosition(
(pos) => {
sendLocation({
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
});
},
(err) => {
toast.error("Lokatsiya olishda xatolik");
console.error(err);
setLocationLoad(false);
},
{
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 0,
},
);
};
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Sidebar - Desktop */} {/* Sidebar - Desktop */}
@@ -55,11 +102,35 @@ export function DashboardLayout({ children }: { children: ReactNode }) {
<ul role="list" className="flex flex-1 flex-col gap-y-1"> <ul role="list" className="flex flex-1 flex-col gap-y-1">
{navItems.map((item) => { {navItems.map((item) => {
const Icon = item.icon; const Icon = item.icon;
const isActive = pathname?.includes(item.href); const isActive =
item.href === "/"
? pathname === "/"
: pathname.startsWith(item.href);
const isLocationItem = item.href === "/location";
return ( return (
<li key={item.href}> <li key={item.href}>
{isLocationItem ? (
<button
onClick={handleSidebarLocationClick}
className={cn(
"group flex gap-x-3 p-3 text-left w-full text-sm font-semibold leading-6 transition-colors",
isActive
? "bg-accent-gradient-soft text-primary rounded-xl-soft shadow-sm"
: "text-sidebar-foreground hover:bg-accent-gradient-soft hover:text-primary rounded-lg",
)}
>
{locationLoad ? (
<Loader2 className="h-5 w-5 animate-spin" />
) : (
<Icon className="h-5 w-5 shrink-0" />
)}
{item.title}
</button>
) : (
<Link <Link
to={`/${locale}${item.href}`} to={item.href}
className={cn( className={cn(
"group flex gap-x-3 p-3 text-sm font-semibold leading-6 transition-colors", "group flex gap-x-3 p-3 text-sm font-semibold leading-6 transition-colors",
isActive isActive
@@ -70,6 +141,7 @@ export function DashboardLayout({ children }: { children: ReactNode }) {
<Icon className="h-5 w-5 shrink-0" /> <Icon className="h-5 w-5 shrink-0" />
{item.title} {item.title}
</Link> </Link>
)}
</li> </li>
); );
})} })}
@@ -105,20 +177,48 @@ export function DashboardLayout({ children }: { children: ReactNode }) {
{/* Mobile Sidebar */} {/* Mobile Sidebar */}
<Sheet open={sidebarOpen} onOpenChange={setSidebarOpen}> <Sheet open={sidebarOpen} onOpenChange={setSidebarOpen}>
<SheetContent side="left" className="w-64 p-0"> <SheetContent side="left" className="w-64 p-0" closedButton={false}>
<div className="flex h-16 shrink-0 items-center border-b border-sidebar-border"> <div className="flex justify-between h-16 px-2 shrink-0 items-center border-b border-sidebar-border">
<img src={Logo} alt="logo" className="w-32 h-12 ml-2" /> <img src={Logo} alt="logo" className="w-32 h-10 ml-2" />
<SheetClose asChild>
<Button size={"icon"} variant={"ghost"}>
<X className="size-5 text-gray-600" />
</Button>
</SheetClose>
</div> </div>
<nav className="flex flex-1 flex-col p-6"> <nav className="flex flex-1 flex-col px-2">
<ul role="list" className="flex flex-1 flex-col gap-y-1"> <ul role="list" className="flex flex-1 flex-col">
{navItems.map((item) => { {navItems.map((item) => {
const Icon = item.icon; const Icon = item.icon;
const isActive = pathname?.includes(item.href); const isActive =
item.href === "/"
? pathname === "/"
: pathname.startsWith(item.href);
const isLocationItem = item.href === "/location";
return ( return (
<li key={item.href}> <li key={item.href}>
{isLocationItem ? (
<button
onClick={handleSidebarLocationClick}
className={cn(
"group flex gap-x-3 p-3 text-left w-full text-sm font-semibold leading-6 transition-colors",
isActive
? "bg-accent-gradient-soft text-primary rounded-xl-soft shadow-sm"
: "text-sidebar-foreground hover:bg-accent-gradient-soft hover:text-primary rounded-lg",
)}
>
{locationLoad ? (
<Loader2 className="h-5 w-5 animate-spin" />
) : (
<Icon className="h-5 w-5 shrink-0" />
)}
{item.title}
</button>
) : (
<Link <Link
to={`/$${item.href}`} to={item.href}
onClick={() => setSidebarOpen(false)}
className={cn( className={cn(
"group flex gap-x-3 p-3 text-sm font-semibold leading-6 transition-colors", "group flex gap-x-3 p-3 text-sm font-semibold leading-6 transition-colors",
isActive isActive
@@ -129,6 +229,7 @@ export function DashboardLayout({ children }: { children: ReactNode }) {
<Icon className="h-5 w-5 shrink-0" /> <Icon className="h-5 w-5 shrink-0" />
{item.title} {item.title}
</Link> </Link>
)}
</li> </li>
); );
})} })}

View File

@@ -17,7 +17,7 @@ export default defineConfig({
port: 5174, port: 5174,
host: true, // barcha hostlarga ruxsat host: true, // barcha hostlarga ruxsat
allowedHosts: [ allowedHosts: [
"factory-epa-announced-adapter.trycloudflare.com", // ngrok host qo'shildi "worth-fathers-turned-diamonds.trycloudflare.com", // ngrok host qo'shildi
], ],
}, },
}); });