@@ -2,11 +2,12 @@ import Button from '@/components/Button'
|
||||
import Filters from '@/components/Filters'
|
||||
import Table from '@/components/Table'
|
||||
import { AddSquare, Edit, More2 } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
import { useDeleteProduct, useGetProducts } from './hooks/useProductData'
|
||||
import { type FC, useState } from 'react'
|
||||
import { useDeleteProduct, useDuplicateProduct, useGetProducts } from './hooks/useProductData'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Paths } from '@/config/Paths'
|
||||
import TrashWithConfrim from '@/components/TrashWithConfrim'
|
||||
import CopyWithConfirm from '@/components/CopyWithConfirm'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
|
||||
@@ -14,6 +15,23 @@ const ProductList: FC = () => {
|
||||
|
||||
const { data: products, refetch } = useGetProducts()
|
||||
const { mutate: deleteProduct, isPending: isDeleting } = useDeleteProduct()
|
||||
const { mutate: duplicateProduct, isPending: isDuplicating } = useDuplicateProduct()
|
||||
const [duplicatingId, setDuplicatingId] = useState<string | null>(null)
|
||||
|
||||
const handleDuplicate = (id: string) => {
|
||||
setDuplicatingId(id)
|
||||
duplicateProduct(id, {
|
||||
onSuccess: () => {
|
||||
refetch()
|
||||
toast.success('محصول با موفقیت کپی شد')
|
||||
setDuplicatingId(null)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
setDuplicatingId(null)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
deleteProduct(id, {
|
||||
@@ -97,6 +115,10 @@ const ProductList: FC = () => {
|
||||
render: (item) => {
|
||||
return (
|
||||
<div className='flex gap-2 items-center'>
|
||||
<CopyWithConfirm
|
||||
onDuplicate={() => handleDuplicate(item.id)}
|
||||
isloading={isDuplicating && duplicatingId === item.id}
|
||||
/>
|
||||
<Link to={Paths.product.update + item.id}>
|
||||
<Edit size={20} color='#0037FF' />
|
||||
</Link>
|
||||
|
||||
@@ -12,9 +12,13 @@ import SwitchComponent from '@/components/Switch'
|
||||
import { useSingleUpload } from '@/pages/uploader/hooks/useUploader'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Paths } from '@/config/Paths'
|
||||
import BackButton from '@/components/BackButton'
|
||||
|
||||
const ProductCategory: FC = () => {
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { data } = useGetCategory()
|
||||
const { mutate, isPending } = useCreateCategory()
|
||||
const { mutate: upload, isPending: isUploading } = useSingleUpload()
|
||||
@@ -29,6 +33,7 @@ const ProductCategory: FC = () => {
|
||||
mutate(values, {
|
||||
onSuccess: () => {
|
||||
toast.success('با موفقیت ذخیره شد')
|
||||
navigate(Paths.product.category.list)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
@@ -64,8 +69,10 @@ const ProductCategory: FC = () => {
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<div className='flex justify-between items-center'>
|
||||
|
||||
<h1 className='text-lg font-light'>دسته جدید</h1>
|
||||
<div className='flex items-center gap-4'>
|
||||
<BackButton to={Paths.product.category.list} />
|
||||
<h1 className='text-lg font-light'>دسته جدید</h1>
|
||||
</div>
|
||||
<Button
|
||||
className='w-fit px-6'
|
||||
isLoading={isPending || isUploading}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Paths } from '@/config/Paths'
|
||||
import BackButton from '@/components/BackButton'
|
||||
|
||||
const CategoryList: FC = () => {
|
||||
|
||||
@@ -82,7 +83,10 @@ const CategoryList: FC = () => {
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<h1 className='text-lg font-light'>دسته بندی محصولات</h1>
|
||||
<div className='flex items-center gap-4'>
|
||||
<BackButton to={Paths.product.list} />
|
||||
<h1 className='text-lg font-light'>دسته بندی محصولات</h1>
|
||||
</div>
|
||||
|
||||
<Link to={Paths.product.category.create}>
|
||||
<Button className='w-fit px-6'>
|
||||
|
||||
@@ -20,8 +20,14 @@ export const useGetCategory = () => {
|
||||
};
|
||||
|
||||
export const useCreateCategory = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: api.createCategory,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["category"],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -92,6 +98,18 @@ export const useDeleteProduct = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useDuplicateProduct = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => api.duplicateProduct(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["products"],
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateAttribute = () => {
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@ export const deleteProduct = async (id: string) => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export const duplicateProduct = async (id: string) => {
|
||||
const { data } = await axios.post(`/admin/products/${id}/duplicate`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createAttribute = async (id: number, params:CreateAttributeType) => {
|
||||
const { data } = await axios.post(`/admin/product/${id}/attribute`, params);
|
||||
return data;
|
||||
|
||||
Reference in New Issue
Block a user