up
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-07 18:57:22 +03:30
parent bdc61398d7
commit aeea803198
8 changed files with 113 additions and 8 deletions
+24 -2
View File
@@ -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>
+9 -2
View File
@@ -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}
+5 -1
View File
@@ -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'>
+18
View File
@@ -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;