This commit is contained in:
Samandar Turgunboyev
2026-01-14 14:38:16 +05:00
parent 6bf98545db
commit aa1e4f0440
5 changed files with 48 additions and 166 deletions

View File

@@ -10,13 +10,9 @@ import { useState } from "react";
const CategoriesList = () => {
const [currentPage, setCurrentPage] = useState(1);
const [search, setSearch] = useState("");
const [editingDistrict, setEditingDistrict] = useState<CategoryItem | null>(
null,
);
const { data, isLoading, isError } = useQuery({
queryKey: ["categories", currentPage, search],
queryKey: ["categories", currentPage],
queryFn: () =>
categories_api.list({
page: currentPage,
@@ -42,14 +38,7 @@ const CategoriesList = () => {
<div className="flex flex-col md:flex-row justify-between items-start md:items-center mb-4 gap-4">
<h1 className="text-2xl font-bold">Kategoriyalar royxati</h1>
<FilterCategory
dialogOpen={dialogOpen}
setDialogOpen={setDialogOpen}
editing={editingDistrict}
setEditing={setEditingDistrict}
search={search}
setSearch={setSearch}
/>
<FilterCategory />
</div>
<TableDistrict
@@ -58,7 +47,6 @@ const CategoriesList = () => {
dialogOpen={dialogOpen}
isLoading={isLoading}
setDialogOpen={setDialogOpen}
setEditingDistrict={setEditingDistrict}
handleDelete={handleDelete}
currentPage={currentPage}
/>

View File

@@ -1,4 +1,3 @@
import { categories_api } from "@/features/districts/lib/api";
import type { CategoryItem } from "@/features/plans/lib/data";
import { Button } from "@/shared/ui/button";
import {
@@ -9,11 +8,8 @@ import {
DialogHeader,
DialogTitle,
} from "@/shared/ui/dialog";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { Loader2, Trash, X } from "lucide-react";
import { X } from "lucide-react";
import { type Dispatch, type SetStateAction } from "react";
import { toast } from "sonner";
interface Props {
opneDelete: boolean;
@@ -22,32 +18,25 @@ interface Props {
discrit: CategoryItem | null;
}
const DeleteDiscrit = ({
opneDelete,
setOpenDelete,
setDiscritDelete,
discrit,
}: Props) => {
const queryClient = useQueryClient();
const DeleteDiscrit = ({ opneDelete, setOpenDelete, discrit }: Props) => {
// const { mutate: deleteDiscrict, isPending } = useMutation({
// mutationFn: (id: string) => categories_api.delete(id),
const { mutate: deleteDiscrict, isPending } = useMutation({
mutationFn: (id: string) => categories_api.delete(id),
onSuccess: () => {
queryClient.refetchQueries({ queryKey: ["categories"] });
toast.success(`Kategoriya o'chirildi`);
setOpenDelete(false);
setDiscritDelete(null);
},
onError: (err: AxiosError) => {
const errMessage = err.response?.data as { message: string };
const messageText = errMessage.message;
toast.error(messageText || "Xatolik yuz berdi", {
richColors: true,
position: "top-center",
});
},
});
// onSuccess: () => {
// queryClient.refetchQueries({ queryKey: ["categories"] });
// toast.success(`Kategoriya o'chirildi`);
// setOpenDelete(false);
// setDiscritDelete(null);
// },
// onError: (err: AxiosError) => {
// const errMessage = err.response?.data as { message: string };
// const messageText = errMessage.message;
// toast.error(messageText || "Xatolik yuz berdi", {
// richColors: true,
// position: "top-center",
// });
// },
// });
return (
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
@@ -55,7 +44,7 @@ const DeleteDiscrit = ({
<DialogHeader>
<DialogTitle>Kategoriyani o'chirish</DialogTitle>
<DialogDescription className="text-md font-semibold">
Siz rostan ham {discrit?.name_uz} kategoriyani o'chirmoqchimisiz
Siz rostan ham {discrit?.name} kategoriyani o'chirmoqchimisiz
</DialogDescription>
</DialogHeader>
<DialogFooter>
@@ -66,10 +55,7 @@ const DeleteDiscrit = ({
<X />
Bekor qilish
</Button>
<Button
variant={"destructive"}
onClick={() => discrit && deleteDiscrict(discrit.id)}
>
{/*<Button variant={"destructive"}>
{isPending ? (
<Loader2 className="animate-spin" />
) : (
@@ -78,7 +64,7 @@ const DeleteDiscrit = ({
O'chirish
</>
)}
</Button>
</Button>*/}
</DialogFooter>
</DialogContent>
</Dialog>

View File

@@ -25,7 +25,6 @@ interface Props {
isError: boolean;
handleDelete: (user: CategoryItem) => void;
setDialogOpen: Dispatch<SetStateAction<boolean>>;
setEditingDistrict: Dispatch<SetStateAction<CategoryItem | null>>;
dialogOpen: boolean;
currentPage: number;
}

View File

@@ -49,29 +49,26 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
const form = useForm<z.infer<typeof createPlanFormData>>({
resolver: zodResolver(createPlanFormData),
defaultValues: {
name_uz: initialValues?.name_uz || "",
name_ru: initialValues?.name_ru || "",
description_uz: initialValues?.description_uz || "",
description_ru: initialValues?.description_ru || "",
category_id: initialValues?.category || "",
unity_id: initialValues?.unity || "",
price: initialValues?.price || 0,
quantity_left: initialValues?.quantity_left || 0,
min_quantity: initialValues?.min_quantity || 0,
is_active: initialValues?.is_active || false,
name_uz: "",
name_ru: "",
description_uz: "",
description_ru: "",
category_id: "",
unity_id: "",
price: 0,
quantity_left: 0,
min_quantity: 0,
is_active: false,
images: [],
article: initialValues?.article || "",
brand: initialValues?.brand || "",
code: initialValues?.code || "",
manufacturer: initialValues?.manufacturer || "",
volume: initialValues?.volume || "",
article: "",
brand: "",
code: "",
manufacturer: "",
volume: "",
},
});
const [openUser, setOpenUser] = useState<boolean>(false);
const [openUnity, setOpenUnity] = useState<boolean>(false);
const [initialImages, setInitialImages] = useState(
initialValues?.images || [],
);
const { mutate, isPending } = useMutation({
mutationFn: (body: FormData) => plans_api.create(body),
@@ -132,7 +129,6 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
return data.data;
},
});
const [removedImageIds, setRemovedImageIds] = useState<string[]>([]);
const onSubmit = (data: z.infer<typeof createPlanFormData>) => {
const formData = new FormData();
@@ -159,8 +155,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
}
if (initialValues) {
removedImageIds.map((e) => formData.append("delete_images", e));
updated({ body: formData, id: initialValues.id });
updated({ body: formData, id: initialValues.id.toString() });
} else {
mutate(formData);
}
@@ -260,9 +255,8 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
!field.value && "text-muted-foreground",
)}
>
{selectedUser &&
typeof selectedUser.name_uz === "string"
? selectedUser.name_uz
{selectedUser && typeof selectedUser.name === "string"
? selectedUser.name
: "Kategoriyani tanlang"}
</Button>
</FormControl>
@@ -297,7 +291,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
: "opacity-0",
)}
/>
{u.name_uz}
{u.name}
</CommandItem>
))}
</CommandGroup>
@@ -589,10 +583,10 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
<FormControl>
<div className="space-y-3">
{/* Agar initialValues'dan rasm bo'lsa ko'rsatish */}
{initialValues?.image && !field.value && (
{initialValues?.images && !field.value && (
<div className="relative w-full h-48 border rounded-xl overflow-hidden">
<img
src={API_URLS.BASE_URL + initialValues.image}
src={API_URLS.BASE_URL + initialValues.images[0].image}
alt="Mavjud rasm"
className="w-full h-full object-contain"
/>
@@ -619,7 +613,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
>
<Upload className="size-10 text-muted-foreground" />
<p className="text-muted-foreground text-lg">
{field.value || initialValues?.image
{field.value || initialValues?.images
? "Yangi rasm tanlash"
: "Rasm tanlang"}
</p>
@@ -652,48 +646,6 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
<FormLabel>Qo'shimcha rasmlar</FormLabel>
<FormControl>
<div className="space-y-3">
{initialImages.length > 0 && (
<div>
<p className="text-sm text-gray-600 mb-2">
Mavjud rasmlar:
</p>
<div className="grid grid-cols-7 gap-2 mb-3">
{initialImages.map((img, idx) => (
<div
key={idx}
className="relative border rounded-xl overflow-hidden"
>
<img
src={API_URLS.BASE_URL + img.image}
alt={`existing-${idx}`}
className="h-14 w-14 object-cover"
/>
<Button
type="button"
onClick={() => {
const removed = initialImages[idx].id;
setRemovedImageIds([
...removedImageIds,
removed,
]);
const updated = initialImages.filter(
(_, i) => i !== idx,
);
setInitialImages(updated);
}}
className="absolute z-[99999] top-1 right-1 bg-red-500 hover:bg-red-600 text-white rounded-full cursor-pointer flex items-center justify-center w-4 h-4"
>
<XIcon className="size-3" />
</Button>
<div className="absolute bottom-0 left-0 right-0 bg-blue-500/80 text-white text-[10px] text-center py-0.5">
Mavjud
</div>
</div>
))}
</div>
</div>
)}
{/* FILE INPUT */}
<Input
type="file"

View File

@@ -1,4 +1,3 @@
import { plans_api } from "@/features/plans/lib/api";
import type { Product } from "@/features/plans/lib/data";
import { Button } from "@/shared/ui/button";
import {
@@ -9,11 +8,8 @@ import {
DialogHeader,
DialogTitle,
} from "@/shared/ui/dialog";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { Loader2, Trash, X } from "lucide-react";
import { X } from "lucide-react";
import type { Dispatch, SetStateAction } from "react";
import { toast } from "sonner";
interface Props {
opneDelete: boolean;
@@ -22,33 +18,7 @@ interface Props {
planDelete: Product | null;
}
const DeletePlan = ({
opneDelete,
setOpenDelete,
planDelete,
setPlanDelete,
}: Props) => {
const queryClient = useQueryClient();
const { mutate: deleteUser, isPending } = useMutation({
mutationFn: (id: string) => plans_api.delete(id),
onSuccess: () => {
queryClient.refetchQueries({ queryKey: ["product_list"] });
toast.success(`Mahsulot o'chirildi`);
setOpenDelete(false);
setPlanDelete(null);
},
onError: (err: AxiosError) => {
const errMessage = err.response?.data as { message: string };
const messageText = errMessage.message;
toast.error(messageText || "Xatolik yuz berdi", {
richColors: true,
position: "top-center",
});
},
});
const DeletePlan = ({ opneDelete, setOpenDelete }: Props) => {
return (
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
<DialogContent>
@@ -66,19 +36,6 @@ const DeletePlan = ({
<X />
Bekor qilish
</Button>
<Button
variant={"destructive"}
onClick={() => planDelete && deleteUser(planDelete.id)}
>
{isPending ? (
<Loader2 className="animate-spin" />
) : (
<>
<Trash />
O'chirish
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>