update
This commit is contained in:
@@ -10,13 +10,9 @@ import { useState } from "react";
|
|||||||
|
|
||||||
const CategoriesList = () => {
|
const CategoriesList = () => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [search, setSearch] = useState("");
|
|
||||||
const [editingDistrict, setEditingDistrict] = useState<CategoryItem | null>(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data, isLoading, isError } = useQuery({
|
const { data, isLoading, isError } = useQuery({
|
||||||
queryKey: ["categories", currentPage, search],
|
queryKey: ["categories", currentPage],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
categories_api.list({
|
categories_api.list({
|
||||||
page: currentPage,
|
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">
|
<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 ro‘yxati</h1>
|
<h1 className="text-2xl font-bold">Kategoriyalar ro‘yxati</h1>
|
||||||
|
|
||||||
<FilterCategory
|
<FilterCategory />
|
||||||
dialogOpen={dialogOpen}
|
|
||||||
setDialogOpen={setDialogOpen}
|
|
||||||
editing={editingDistrict}
|
|
||||||
setEditing={setEditingDistrict}
|
|
||||||
search={search}
|
|
||||||
setSearch={setSearch}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TableDistrict
|
<TableDistrict
|
||||||
@@ -58,7 +47,6 @@ const CategoriesList = () => {
|
|||||||
dialogOpen={dialogOpen}
|
dialogOpen={dialogOpen}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
setDialogOpen={setDialogOpen}
|
setDialogOpen={setDialogOpen}
|
||||||
setEditingDistrict={setEditingDistrict}
|
|
||||||
handleDelete={handleDelete}
|
handleDelete={handleDelete}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { categories_api } from "@/features/districts/lib/api";
|
|
||||||
import type { CategoryItem } from "@/features/plans/lib/data";
|
import type { CategoryItem } from "@/features/plans/lib/data";
|
||||||
import { Button } from "@/shared/ui/button";
|
import { Button } from "@/shared/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -9,11 +8,8 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/shared/ui/dialog";
|
} from "@/shared/ui/dialog";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { X } from "lucide-react";
|
||||||
import type { AxiosError } from "axios";
|
|
||||||
import { Loader2, Trash, X } from "lucide-react";
|
|
||||||
import { type Dispatch, type SetStateAction } from "react";
|
import { type Dispatch, type SetStateAction } from "react";
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
opneDelete: boolean;
|
opneDelete: boolean;
|
||||||
@@ -22,32 +18,25 @@ interface Props {
|
|||||||
discrit: CategoryItem | null;
|
discrit: CategoryItem | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeleteDiscrit = ({
|
const DeleteDiscrit = ({ opneDelete, setOpenDelete, discrit }: Props) => {
|
||||||
opneDelete,
|
// const { mutate: deleteDiscrict, isPending } = useMutation({
|
||||||
setOpenDelete,
|
// mutationFn: (id: string) => categories_api.delete(id),
|
||||||
setDiscritDelete,
|
|
||||||
discrit,
|
|
||||||
}: Props) => {
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const { mutate: deleteDiscrict, isPending } = useMutation({
|
// onSuccess: () => {
|
||||||
mutationFn: (id: string) => categories_api.delete(id),
|
// queryClient.refetchQueries({ queryKey: ["categories"] });
|
||||||
|
// toast.success(`Kategoriya o'chirildi`);
|
||||||
onSuccess: () => {
|
// setOpenDelete(false);
|
||||||
queryClient.refetchQueries({ queryKey: ["categories"] });
|
// setDiscritDelete(null);
|
||||||
toast.success(`Kategoriya o'chirildi`);
|
// },
|
||||||
setOpenDelete(false);
|
// onError: (err: AxiosError) => {
|
||||||
setDiscritDelete(null);
|
// const errMessage = err.response?.data as { message: string };
|
||||||
},
|
// const messageText = errMessage.message;
|
||||||
onError: (err: AxiosError) => {
|
// toast.error(messageText || "Xatolik yuz berdi", {
|
||||||
const errMessage = err.response?.data as { message: string };
|
// richColors: true,
|
||||||
const messageText = errMessage.message;
|
// position: "top-center",
|
||||||
toast.error(messageText || "Xatolik yuz berdi", {
|
// });
|
||||||
richColors: true,
|
// },
|
||||||
position: "top-center",
|
// });
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
|
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
|
||||||
@@ -55,7 +44,7 @@ const DeleteDiscrit = ({
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Kategoriyani o'chirish</DialogTitle>
|
<DialogTitle>Kategoriyani o'chirish</DialogTitle>
|
||||||
<DialogDescription className="text-md font-semibold">
|
<DialogDescription className="text-md font-semibold">
|
||||||
Siz rostan ham {discrit?.name_uz} kategoriyani o'chirmoqchimisiz
|
Siz rostan ham {discrit?.name} kategoriyani o'chirmoqchimisiz
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
@@ -66,10 +55,7 @@ const DeleteDiscrit = ({
|
|||||||
<X />
|
<X />
|
||||||
Bekor qilish
|
Bekor qilish
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{/*<Button variant={"destructive"}>
|
||||||
variant={"destructive"}
|
|
||||||
onClick={() => discrit && deleteDiscrict(discrit.id)}
|
|
||||||
>
|
|
||||||
{isPending ? (
|
{isPending ? (
|
||||||
<Loader2 className="animate-spin" />
|
<Loader2 className="animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
@@ -78,7 +64,7 @@ const DeleteDiscrit = ({
|
|||||||
O'chirish
|
O'chirish
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>*/}
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ interface Props {
|
|||||||
isError: boolean;
|
isError: boolean;
|
||||||
handleDelete: (user: CategoryItem) => void;
|
handleDelete: (user: CategoryItem) => void;
|
||||||
setDialogOpen: Dispatch<SetStateAction<boolean>>;
|
setDialogOpen: Dispatch<SetStateAction<boolean>>;
|
||||||
setEditingDistrict: Dispatch<SetStateAction<CategoryItem | null>>;
|
|
||||||
dialogOpen: boolean;
|
dialogOpen: boolean;
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,29 +49,26 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
const form = useForm<z.infer<typeof createPlanFormData>>({
|
const form = useForm<z.infer<typeof createPlanFormData>>({
|
||||||
resolver: zodResolver(createPlanFormData),
|
resolver: zodResolver(createPlanFormData),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name_uz: initialValues?.name_uz || "",
|
name_uz: "",
|
||||||
name_ru: initialValues?.name_ru || "",
|
name_ru: "",
|
||||||
description_uz: initialValues?.description_uz || "",
|
description_uz: "",
|
||||||
description_ru: initialValues?.description_ru || "",
|
description_ru: "",
|
||||||
category_id: initialValues?.category || "",
|
category_id: "",
|
||||||
unity_id: initialValues?.unity || "",
|
unity_id: "",
|
||||||
price: initialValues?.price || 0,
|
price: 0,
|
||||||
quantity_left: initialValues?.quantity_left || 0,
|
quantity_left: 0,
|
||||||
min_quantity: initialValues?.min_quantity || 0,
|
min_quantity: 0,
|
||||||
is_active: initialValues?.is_active || false,
|
is_active: false,
|
||||||
images: [],
|
images: [],
|
||||||
article: initialValues?.article || "",
|
article: "",
|
||||||
brand: initialValues?.brand || "",
|
brand: "",
|
||||||
code: initialValues?.code || "",
|
code: "",
|
||||||
manufacturer: initialValues?.manufacturer || "",
|
manufacturer: "",
|
||||||
volume: initialValues?.volume || "",
|
volume: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [openUser, setOpenUser] = useState<boolean>(false);
|
const [openUser, setOpenUser] = useState<boolean>(false);
|
||||||
const [openUnity, setOpenUnity] = useState<boolean>(false);
|
const [openUnity, setOpenUnity] = useState<boolean>(false);
|
||||||
const [initialImages, setInitialImages] = useState(
|
|
||||||
initialValues?.images || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
const { mutate, isPending } = useMutation({
|
const { mutate, isPending } = useMutation({
|
||||||
mutationFn: (body: FormData) => plans_api.create(body),
|
mutationFn: (body: FormData) => plans_api.create(body),
|
||||||
@@ -132,7 +129,6 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
return data.data;
|
return data.data;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [removedImageIds, setRemovedImageIds] = useState<string[]>([]);
|
|
||||||
|
|
||||||
const onSubmit = (data: z.infer<typeof createPlanFormData>) => {
|
const onSubmit = (data: z.infer<typeof createPlanFormData>) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
@@ -159,8 +155,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (initialValues) {
|
if (initialValues) {
|
||||||
removedImageIds.map((e) => formData.append("delete_images", e));
|
updated({ body: formData, id: initialValues.id.toString() });
|
||||||
updated({ body: formData, id: initialValues.id });
|
|
||||||
} else {
|
} else {
|
||||||
mutate(formData);
|
mutate(formData);
|
||||||
}
|
}
|
||||||
@@ -260,9 +255,8 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
!field.value && "text-muted-foreground",
|
!field.value && "text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{selectedUser &&
|
{selectedUser && typeof selectedUser.name === "string"
|
||||||
typeof selectedUser.name_uz === "string"
|
? selectedUser.name
|
||||||
? selectedUser.name_uz
|
|
||||||
: "Kategoriyani tanlang"}
|
: "Kategoriyani tanlang"}
|
||||||
</Button>
|
</Button>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -297,7 +291,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
: "opacity-0",
|
: "opacity-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{u.name_uz}
|
{u.name}
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
@@ -589,10 +583,10 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{/* Agar initialValues'dan rasm bo'lsa ko'rsatish */}
|
{/* 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">
|
<div className="relative w-full h-48 border rounded-xl overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={API_URLS.BASE_URL + initialValues.image}
|
src={API_URLS.BASE_URL + initialValues.images[0].image}
|
||||||
alt="Mavjud rasm"
|
alt="Mavjud rasm"
|
||||||
className="w-full h-full object-contain"
|
className="w-full h-full object-contain"
|
||||||
/>
|
/>
|
||||||
@@ -619,7 +613,7 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
>
|
>
|
||||||
<Upload className="size-10 text-muted-foreground" />
|
<Upload className="size-10 text-muted-foreground" />
|
||||||
<p className="text-muted-foreground text-lg">
|
<p className="text-muted-foreground text-lg">
|
||||||
{field.value || initialValues?.image
|
{field.value || initialValues?.images
|
||||||
? "Yangi rasm tanlash"
|
? "Yangi rasm tanlash"
|
||||||
: "Rasm tanlang"}
|
: "Rasm tanlang"}
|
||||||
</p>
|
</p>
|
||||||
@@ -652,48 +646,6 @@ const AddedPlan = ({ initialValues, setDialogOpen }: Props) => {
|
|||||||
<FormLabel>Qo'shimcha rasmlar</FormLabel>
|
<FormLabel>Qo'shimcha rasmlar</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="space-y-3">
|
<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 */}
|
{/* FILE INPUT */}
|
||||||
<Input
|
<Input
|
||||||
type="file"
|
type="file"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { plans_api } from "@/features/plans/lib/api";
|
|
||||||
import type { Product } from "@/features/plans/lib/data";
|
import type { Product } from "@/features/plans/lib/data";
|
||||||
import { Button } from "@/shared/ui/button";
|
import { Button } from "@/shared/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -9,11 +8,8 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/shared/ui/dialog";
|
} from "@/shared/ui/dialog";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { X } from "lucide-react";
|
||||||
import type { AxiosError } from "axios";
|
|
||||||
import { Loader2, Trash, X } from "lucide-react";
|
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
opneDelete: boolean;
|
opneDelete: boolean;
|
||||||
@@ -22,33 +18,7 @@ interface Props {
|
|||||||
planDelete: Product | null;
|
planDelete: Product | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeletePlan = ({
|
const DeletePlan = ({ opneDelete, setOpenDelete }: Props) => {
|
||||||
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",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
|
<Dialog open={opneDelete} onOpenChange={setOpenDelete}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -66,19 +36,6 @@ const DeletePlan = ({
|
|||||||
<X />
|
<X />
|
||||||
Bekor qilish
|
Bekor qilish
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
variant={"destructive"}
|
|
||||||
onClick={() => planDelete && deleteUser(planDelete.id)}
|
|
||||||
>
|
|
||||||
{isPending ? (
|
|
||||||
<Loader2 className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Trash />
|
|
||||||
O'chirish
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
Reference in New Issue
Block a user