This commit is contained in:
Samandar Turgunboyev
2025-11-27 15:57:26 +05:00
parent 980fb1dd13
commit 969e32be09
177 changed files with 17023 additions and 995 deletions

View File

@@ -0,0 +1,359 @@
"use client";
import { district_api } from "@/features/district/lib/api";
import { doctor_api } from "@/features/doctor/lib/api";
import { location_api, type CreateLocation } from "@/features/home/lib/api";
import { object_api } from "@/features/object/lib/api";
import { pharmacy_api } from "@/features/phamarcy/lib/api";
import { Button } from "@/shared/ui/button";
import { Card, CardDescription, CardHeader, CardTitle } from "@/shared/ui/card";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/shared/ui/dialog";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/shared/ui/table";
import { DashboardLayout } from "@/widgets/dashboard-layout/ui";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { AxiosError } from "axios";
import { Loader2, MapPin, Send } from "lucide-react";
import React, { useState } from "react";
import { toast } from "sonner";
import { columns } from "../lib/column";
const MyLocation: React.FC = () => {
const [showMainModal, setShowMainModal] = useState<boolean>(false);
const queryClinent = useQueryClient();
const [showSelectModal, setShowSelectModal] = useState<boolean>(false);
const [selectType, setSelectType] = useState<
"district" | "object" | "doctor" | "pharm" | null
>(null);
const [loadingButtonId, setLoadingButtonId] = useState<number | null>(null);
const mutation = useMutation({
mutationFn: (body: CreateLocation) => location_api.create_location(body),
onSuccess: () => {
toast.success("Lokatsiya jo'natildi");
setShowSelectModal(false);
setLoadingButtonId(null);
queryClinent.refetchQueries({ queryKey: ["location_list"] });
},
onError: (error: AxiosError) => {
const data = error.response?.data as { message?: string };
const errorData = error.response?.data as {
messages?: {
token_class: string;
token_type: string;
message: string;
}[];
};
const errorName = error.response?.data as {
data?: {
name: string[];
};
};
toast.error(
errorName.data?.name?.[0] ||
data.message ||
errorData?.messages?.[0]?.message ||
"Xatolik yuz berdi",
);
setLoadingButtonId(null);
},
});
const { data: location } = useQuery({
queryKey: ["location_list"],
queryFn: () => location_api.list_location(),
select(data) {
return data.data.data;
},
});
const { data: districts, isLoading: isDistrictsLoading } = useQuery({
queryKey: ["my_disctrict"],
queryFn: () => district_api.getDiscrict(),
select: (data) => data.data.data,
});
const { data: objects, isLoading: isObjectsLoading } = useQuery({
queryKey: ["object_list"],
queryFn: () => object_api.getAll({}),
select: (data) => data.data.data,
});
const { data: doctors, isLoading: isDoctorsLoading } = useQuery({
queryKey: ["doctor_list"],
queryFn: () => doctor_api.list(),
select: (data) => data.data.data,
});
const { data: pharm, isLoading: isPharmLoading } = useQuery({
queryKey: ["pharmacy_list"],
queryFn: () => pharmacy_api.list(),
select: (data) => data.data.data,
});
const getOptions = () => {
if (selectType === "district") return districts;
if (selectType === "object") return objects;
if (selectType === "doctor") return doctors;
if (selectType === "pharm") return pharm;
return [];
};
const isLoading = () => {
if (selectType === "district") return isDistrictsLoading;
if (selectType === "object") return isObjectsLoading;
if (selectType === "doctor") return isDoctorsLoading;
if (selectType === "pharm") return isPharmLoading;
return false;
};
const typeLabel = (type: "district" | "object" | "doctor" | "pharm") => {
if (type === "district") return "Tuman";
if (type === "object") return "Obyekt";
if (type === "doctor") return "Shifokor";
if (type === "pharm") return "Dorixona";
};
const handleAddLocation = (id: number) => {
if (!selectType) return;
setLoadingButtonId(id); // faqat shu button loading
navigator.geolocation.getCurrentPosition(
(position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
const body: CreateLocation = {
latitude,
longitude,
};
switch (selectType) {
case "district":
body.district_id = id;
break;
case "object":
body.place_id = id;
break;
case "doctor":
body.doctor_id = id;
break;
case "pharm":
body.pharmacy_id = id;
break;
}
mutation.mutate(body);
},
() => {
toast.error("Geolokatsiya olinmadi");
setLoadingButtonId(null);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 0 },
);
};
const table = useReactTable({
data: location || [],
columns: columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
});
return (
<DashboardLayout>
<div className="space-y-4">
<Card>
<CardHeader className="flex flex-col">
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center">
<MapPin className="text-white" size={24} />
</div>
<div>
<CardTitle className="text-2xl">Lokatsiya Tizimi</CardTitle>
<CardDescription>{"Manzil jo'natish va tarix"}</CardDescription>
</div>
</div>
</CardHeader>
</Card>
{/* Main Modal */}
<Dialog open={showMainModal} onOpenChange={setShowMainModal}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="text-2xl">
{"Nimani jo'natasiz?"}
</DialogTitle>
</DialogHeader>
<div className="space-y-3 mt-4">
{(["district", "object", "doctor", "pharm"] as const).map(
(type) => (
<Button
key={type}
onClick={() => {
setSelectType(type);
setShowSelectModal(true);
setShowMainModal(false);
}}
className="w-full h-12 text-lg"
variant="outline"
>
{typeLabel(type)}
</Button>
),
)}
</div>
</DialogContent>
</Dialog>
{/* Select Modal */}
<Dialog open={showSelectModal} onOpenChange={setShowSelectModal}>
<DialogContent className="sm:max-w-md h-[60%] flex flex-col justify-start overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-2xl">
Mavjud {selectType && typeLabel(selectType)}lar
</DialogTitle>
</DialogHeader>
<div className="space-y-2 flex flex-col flex-1">
{isLoading() ? (
<div className="flex flex-col items-center justify-center py-12 gap-3">
<Loader2 className="h-8 w-8 animate-spin text-blue-500" />
<p className="text-muted-foreground">Yuklanmoqda...</p>
</div>
) : getOptions()?.length === 0 ? (
<div className="flex items-center justify-center py-12">
<p className="text-muted-foreground">Ma'lumot topilmadi</p>
</div>
) : (
getOptions()?.map((item) => {
const id = item.id;
const label =
"name" in item
? item.name
: `${item.first_name} ${item.last_name}`;
const isButtonLoading = loadingButtonId === id;
return (
<Button
key={id}
onClick={() => handleAddLocation(id)}
variant="outline"
className="w-full justify-start h-auto py-3 flex items-center gap-2"
disabled={isButtonLoading}
>
<MapPin className="h-4 w-4" />
{isButtonLoading ? (
<>
<Loader2 className="h-4 w-4 animate-spin" />
Yuklanmoqda...
</>
) : (
label
)}
</Button>
);
})
)}
</div>
<Button
onClick={() => setShowSelectModal(false)}
variant="outline"
className="w-full mt-2"
>
Bekor qilish
</Button>
</DialogContent>
</Dialog>
<div className="flex justify-end">
<Button onClick={() => setShowMainModal(true)} className="gap-2">
<Send size={20} />
<span>{"Lokatsiya Jo'natish"}</span>
</Button>
</div>
{/* Table */}
<div className="w-full">
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead
key={header.id}
className="border-r text-center"
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell
key={cell.id}
className="border-r text-center"
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</div>
</div>
</DashboardLayout>
);
};
export default MyLocation;