352 lines
9.4 KiB
TypeScript
352 lines
9.4 KiB
TypeScript
import {
|
||
hotelFeatureCreate,
|
||
hotelFeatureDelete,
|
||
hotelFeatureDetail,
|
||
hotelFeatureUpdate,
|
||
} from "@/pages/tours/lib/api";
|
||
import { FeatureColumns } from "@/pages/tours/lib/column";
|
||
import type { HotelFeatures } from "@/pages/tours/lib/type";
|
||
import { Button } from "@/shared/ui/button";
|
||
import { Dialog, DialogContent } from "@/shared/ui/dialog";
|
||
import {
|
||
Form,
|
||
FormControl,
|
||
FormField,
|
||
FormItem,
|
||
FormLabel,
|
||
FormMessage,
|
||
} from "@/shared/ui/form";
|
||
import { Input } from "@/shared/ui/input";
|
||
import {
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableHead,
|
||
TableHeader,
|
||
TableRow,
|
||
} from "@/shared/ui/table";
|
||
import RealPagination from "@/widgets/real-pagination/ui/RealPagination";
|
||
import { zodResolver } from "@hookform/resolvers/zod";
|
||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||
import {
|
||
flexRender,
|
||
getCoreRowModel,
|
||
useReactTable,
|
||
} from "@tanstack/react-table";
|
||
import { Loader, PlusIcon } from "lucide-react";
|
||
import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
|
||
import { useForm } from "react-hook-form";
|
||
import { useTranslation } from "react-i18next";
|
||
import { toast } from "sonner";
|
||
import z from "zod";
|
||
|
||
const formSchema = z.object({
|
||
name: z.string().min(1, { message: "Majburiy maydon" }),
|
||
name_ru: z.string().min(1, { message: "Majburiy maydon" }),
|
||
});
|
||
|
||
const FeaturesTable = ({
|
||
data,
|
||
page,
|
||
pageSize,
|
||
setActiveTab,
|
||
setFeatureId,
|
||
}: {
|
||
page: number;
|
||
pageSize: number;
|
||
setActiveTab: Dispatch<SetStateAction<string>>;
|
||
setFeatureId: Dispatch<SetStateAction<number | null>>;
|
||
data:
|
||
| {
|
||
links: {
|
||
previous: string;
|
||
next: string;
|
||
};
|
||
total_items: number;
|
||
total_pages: number;
|
||
page_size: number;
|
||
current_page: number;
|
||
results: HotelFeatures[];
|
||
}
|
||
| undefined;
|
||
}) => {
|
||
const { t } = useTranslation();
|
||
const [open, setOpen] = useState<boolean>(false);
|
||
const [editId, setEditId] = useState<number | null>(null);
|
||
const queryClient = useQueryClient();
|
||
const [types, setTypes] = useState<"edit" | "create">("create");
|
||
|
||
const handleEdit = (id: number) => {
|
||
setTypes("edit");
|
||
setOpen(true);
|
||
setEditId(id);
|
||
};
|
||
|
||
const { data: badgeDetail } = useQuery({
|
||
queryKey: ["detail_feature", editId],
|
||
queryFn: () => hotelFeatureDetail({ id: editId! }),
|
||
enabled: !!editId,
|
||
});
|
||
|
||
const { mutate: deleteMutate } = useMutation({
|
||
mutationFn: ({ id }: { id: number }) => hotelFeatureDelete({ id }),
|
||
onSuccess: () => {
|
||
queryClient.refetchQueries({ queryKey: ["detail_feature"] });
|
||
queryClient.refetchQueries({ queryKey: ["all_feature"] });
|
||
setOpen(false);
|
||
form.reset();
|
||
},
|
||
onError: () => {
|
||
toast.error(t("Xatolik yuz berdi"), {
|
||
position: "top-center",
|
||
richColors: true,
|
||
});
|
||
},
|
||
});
|
||
|
||
const handleDelete = (id: number) => {
|
||
deleteMutate({ id });
|
||
};
|
||
|
||
const columns = FeatureColumns(
|
||
handleEdit,
|
||
handleDelete,
|
||
t,
|
||
setActiveTab,
|
||
setFeatureId,
|
||
);
|
||
|
||
const { mutate: create, isPending } = useMutation({
|
||
mutationFn: ({
|
||
body,
|
||
}: {
|
||
body: {
|
||
hotel_feature_type_name: string;
|
||
hotel_feature_type_name_ru: string;
|
||
};
|
||
}) => hotelFeatureCreate({ body }),
|
||
onSuccess: () => {
|
||
queryClient.refetchQueries({ queryKey: ["detail_feature"] });
|
||
queryClient.refetchQueries({ queryKey: ["all_feature"] });
|
||
setOpen(false);
|
||
form.reset();
|
||
},
|
||
onError: () => {
|
||
toast.error(t("Xatolik yuz berdi"), {
|
||
position: "top-center",
|
||
richColors: true,
|
||
});
|
||
},
|
||
});
|
||
|
||
const { mutate: update, isPending: updatePending } = useMutation({
|
||
mutationFn: ({
|
||
body,
|
||
id,
|
||
}: {
|
||
id: number;
|
||
body: {
|
||
hotel_feature_type_name: string;
|
||
hotel_feature_type_name_ru: string;
|
||
};
|
||
}) => hotelFeatureUpdate({ body, id }),
|
||
onSuccess: () => {
|
||
queryClient.refetchQueries({ queryKey: ["detail_feature"] });
|
||
queryClient.refetchQueries({ queryKey: ["all_feature"] });
|
||
setOpen(false);
|
||
form.reset();
|
||
},
|
||
onError: () => {
|
||
toast.error(t("Xatolik yuz berdi"), {
|
||
position: "top-center",
|
||
richColors: true,
|
||
});
|
||
},
|
||
});
|
||
|
||
const form = useForm<z.infer<typeof formSchema>>({
|
||
resolver: zodResolver(formSchema),
|
||
defaultValues: {
|
||
name: "",
|
||
name_ru: "",
|
||
},
|
||
});
|
||
|
||
useEffect(() => {
|
||
if (badgeDetail) {
|
||
form.setValue("name", badgeDetail.data.data.hotel_feature_type_name_uz);
|
||
form.setValue(
|
||
"name_ru",
|
||
badgeDetail.data.data.hotel_feature_type_name_ru,
|
||
);
|
||
}
|
||
}, [editId, badgeDetail]);
|
||
|
||
function onSubmit(values: z.infer<typeof formSchema>) {
|
||
if (types === "create") {
|
||
create({
|
||
body: {
|
||
hotel_feature_type_name: values.name,
|
||
hotel_feature_type_name_ru: values.name_ru,
|
||
},
|
||
});
|
||
} else if (types === "edit" && editId) {
|
||
update({
|
||
id: editId,
|
||
body: {
|
||
hotel_feature_type_name: values.name,
|
||
hotel_feature_type_name_ru: values.name_ru,
|
||
},
|
||
});
|
||
}
|
||
}
|
||
|
||
const table = useReactTable({
|
||
data: data?.results ?? [],
|
||
columns,
|
||
getCoreRowModel: getCoreRowModel(),
|
||
manualPagination: true,
|
||
pageCount: data?.total_pages ?? 0,
|
||
state: {
|
||
pagination: {
|
||
pageIndex: page - 1,
|
||
pageSize: pageSize,
|
||
},
|
||
},
|
||
});
|
||
|
||
return (
|
||
<>
|
||
<div className="flex justify-end">
|
||
<Button
|
||
variant="default"
|
||
onClick={() => {
|
||
setOpen(true);
|
||
setTypes("create");
|
||
form.reset();
|
||
}}
|
||
>
|
||
<PlusIcon className="mr-2" />
|
||
{t("Qo‘shish")}
|
||
</Button>
|
||
</div>
|
||
|
||
<div className="border border-gray-700 rounded-md overflow-hidden mt-4">
|
||
<Table key={data?.current_page}>
|
||
<TableHeader>
|
||
{table.getHeaderGroups().map((headerGroup) => (
|
||
<TableRow key={headerGroup.id}>
|
||
{headerGroup.headers.map((header) => (
|
||
<TableHead key={header.id}>
|
||
{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}>
|
||
{row.getVisibleCells().map((cell) => (
|
||
<TableCell key={cell.id}>
|
||
{flexRender(
|
||
cell.column.columnDef.cell,
|
||
cell.getContext(),
|
||
)}
|
||
</TableCell>
|
||
))}
|
||
</TableRow>
|
||
))
|
||
) : (
|
||
<TableRow>
|
||
<TableCell
|
||
colSpan={columns.length}
|
||
className="h-24 text-center text-gray-400"
|
||
>
|
||
{t("Ma'lumot topilmadi")}
|
||
</TableCell>
|
||
</TableRow>
|
||
)}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
|
||
<RealPagination
|
||
table={table}
|
||
totalPages={data?.total_pages}
|
||
namePage="pageFeature"
|
||
namePageSize="pageSizeFeature"
|
||
/>
|
||
|
||
<Dialog open={open} onOpenChange={setOpen}>
|
||
<DialogContent>
|
||
<p className="text-xl">
|
||
{types === "create" ? t("Saqlash") : t("Tahrirlash")}
|
||
</p>
|
||
<Form {...form}>
|
||
<form
|
||
onSubmit={form.handleSubmit(onSubmit)}
|
||
className="space-y-6 p-2"
|
||
>
|
||
<FormField
|
||
control={form.control}
|
||
name="name"
|
||
render={({ field }) => (
|
||
<FormItem>
|
||
<FormLabel>{t("Nomi")}</FormLabel>
|
||
<FormControl>
|
||
<Input placeholder={t("Nomi")} {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
<FormField
|
||
control={form.control}
|
||
name="name_ru"
|
||
render={({ field }) => (
|
||
<FormItem>
|
||
<FormLabel>{t("Nomi (ru)")}</FormLabel>
|
||
<FormControl>
|
||
<Input placeholder={t("Nomi (ru)")} {...field} />
|
||
</FormControl>
|
||
<FormMessage />
|
||
</FormItem>
|
||
)}
|
||
/>
|
||
|
||
<div className="flex justify-end gap-4">
|
||
<Button
|
||
type="button"
|
||
onClick={() => setOpen(false)}
|
||
className="border-slate-600 text-white hover:bg-gray-600 bg-gray-600"
|
||
>
|
||
{t("Bekor qilish")}
|
||
</Button>
|
||
<Button type="submit">
|
||
{isPending || updatePending ? (
|
||
<Loader className="animate-spin" />
|
||
) : types === "create" ? (
|
||
t("Saqlash")
|
||
) : (
|
||
t("Tahrirlash")
|
||
)}
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
</Form>
|
||
</DialogContent>
|
||
</Dialog>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default FeaturesTable;
|