Files
gastro-admin/src/features/plans/ui/PalanTable.tsx
Samandar Turgunboyev bd1cf26c46 complated
2026-02-06 20:01:44 +05:00

259 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { plans_api } from "@/features/plans/lib/api";
import type { Product } from "@/features/plans/lib/data";
import { API_URLS } from "@/shared/config/api/URLs";
import { Button } from "@/shared/ui/button";
import { Checkbox } from "@/shared/ui/checkbox";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/shared/ui/table";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Eye, Loader2, Trash2 } from "lucide-react";
import type { Dispatch, SetStateAction } from "react";
import { toast } from "sonner";
interface Props {
products: Product[] | [];
isLoading: boolean;
isFetching: boolean;
setIsAllPagesSelected: Dispatch<SetStateAction<boolean>>;
isError: boolean;
setEditingProduct: Dispatch<SetStateAction<Product | null>>;
setDetailOpen: Dispatch<SetStateAction<boolean>>;
handleDelete: (product: Product) => void;
selectedProducts: number[];
setSelectedProducts: Dispatch<SetStateAction<number[]>>;
handleBulkDelete: () => void;
totalCount: number;
count: number;
handleSelectAllPages: () => void;
isAllPagesSelected: boolean;
}
const ProductTable = ({
products,
isLoading,
isFetching,
isError,
setEditingProduct,
setIsAllPagesSelected,
setDetailOpen,
selectedProducts,
setSelectedProducts,
handleBulkDelete,
totalCount,
handleSelectAllPages,
isAllPagesSelected,
}: Props) => {
const queryClient = useQueryClient();
const { mutate, isPending } = useMutation({
mutationFn: ({
id,
body,
}: {
id: number;
body: { payment_type: "cash" | "card" };
}) => plans_api.update_payment_type({ id, body }),
onSuccess: () => {
queryClient.refetchQueries({ queryKey: ["product_list"] });
toast.success("Tolov turi yangilandi", {
richColors: true,
position: "top-center",
});
},
onError: () => {
toast.error("Xatolik yuz berdi", {
richColors: true,
position: "top-center",
});
},
});
if (isLoading || isFetching) {
return (
<div className="flex h-full items-center justify-center">
<Loader2 className="h-6 w-6 animate-spin" />
</div>
);
}
if (isError) {
return (
<div className="flex h-full items-center justify-center text-red-600">
Maʼlumotlarni yuklashda xatolik yuz berdi
</div>
);
}
const currentPageIds = products.map((p) => p.id);
const isAllSelected =
isAllPagesSelected ||
(products.length > 0 &&
currentPageIds.every((id) => selectedProducts.includes(id)));
const isSomeSelected =
currentPageIds.some((id) => selectedProducts.includes(id)) &&
!currentPageIds.every((id) => selectedProducts.includes(id));
const handleSelectAll = (checked: boolean) => {
if (checked) {
setSelectedProducts(
Array.from(new Set([...selectedProducts, ...currentPageIds])),
);
} else {
setSelectedProducts(
selectedProducts.filter((id) => !currentPageIds.includes(id)),
);
if (isAllPagesSelected) setIsAllPagesSelected(false);
}
};
const handleSelectProduct = (productId: number, checked: boolean) => {
if (checked) setSelectedProducts([...selectedProducts, productId]);
else setSelectedProducts(selectedProducts.filter((id) => id !== productId));
};
return (
<div className="flex-1 overflow-auto">
{selectedProducts.length > 0 && (
<div className="mb-4 space-y-2">
<div className="flex items-center justify-between bg-blue-50 p-4 rounded-lg border border-blue-200">
<span className="text-sm font-medium text-blue-900">
{`${selectedProducts.length} ta mahsulot tanlandi`}
</span>
<div className="flex gap-2">
{!isAllPagesSelected && totalCount > products.length && (
<Button
size="sm"
variant="outline"
onClick={handleSelectAllPages}
className="cursor-pointer border-blue-500 text-blue-700 hover:bg-blue-100"
>
Barcha {totalCount} ta mahsulotni tanlash
</Button>
)}
<Button
size="sm"
variant="destructive"
onClick={handleBulkDelete}
className="cursor-pointer"
>
<Trash2 className="h-4 w-4 mr-2" />
Tanlanganlarni o'chirish
</Button>
</div>
</div>
</div>
)}
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[50px]">
<Checkbox
checked={isAllSelected}
onCheckedChange={handleSelectAll}
aria-label="Barchasini tanlash"
className={
isSomeSelected ? "data-[state=checked]:bg-blue-500" : ""
}
/>
</TableHead>
<TableHead>ID</TableHead>
<TableHead>Rasmi</TableHead>
<TableHead>Nomi</TableHead>
<TableHead>Tavsif</TableHead>
<TableHead>Narx turi</TableHead>
<TableHead className="text-end">Harakatlar</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{products.map((product, index) => {
const isSelected = selectedProducts.includes(product.id);
return (
<TableRow
key={product.id}
className={isSelected ? "bg-blue-50" : ""}
>
<TableCell>
<Checkbox
checked={isSelected}
onCheckedChange={(checked) =>
handleSelectProduct(product.id, checked as boolean)
}
aria-label={`${product.name} tanlash`}
/>
</TableCell>
<TableCell>{index + 1}</TableCell>
<TableCell>
<img
src={
product.images.length > 0
? API_URLS.BASE_URL + product.images[0].image
: "/logo.png"
}
alt={product.name}
className="w-16 h-16 object-cover rounded"
/>
</TableCell>
<TableCell>{product.name}</TableCell>
<TableCell>{product.short_name?.slice(0, 15)}...</TableCell>
<TableCell>
<Select
value={product.payment_type ?? ""}
disabled={isPending}
onValueChange={(value) => {
mutate({
id: product.id,
body: {
payment_type: value as "cash" | "card",
},
});
}}
>
<SelectTrigger className="w-full max-w-48">
<SelectValue placeholder="To'lov turi" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="cash">Naqd</SelectItem>
<SelectItem value="card">Karta</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</TableCell>
<TableCell className="space-x-2 text-right">
<Button
size="sm"
variant="outline"
onClick={() => {
setEditingProduct(product);
setDetailOpen(true);
}}
>
<Eye className="h-4 w-4" />
</Button>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
};
export default ProductTable;