delete and edit category attribute
This commit is contained in:
@@ -6,7 +6,8 @@ import { AttributesModal } from './components'
|
|||||||
import { useAttributesLogic } from './hooks/useAttributesLogic'
|
import { useAttributesLogic } from './hooks/useAttributesLogic'
|
||||||
import { useGetCategoryAttributes } from './hooks/useCategoryData'
|
import { useGetCategoryAttributes } from './hooks/useCategoryData'
|
||||||
import { type CategoryAttributeType } from './types/Types'
|
import { type CategoryAttributeType } from './types/Types'
|
||||||
import { Add, Edit, Trash } from 'iconsax-react'
|
import { Add, Edit } from 'iconsax-react'
|
||||||
|
import TrashWithConfrim from '../../components/TrashWithConfrim'
|
||||||
|
|
||||||
const Attributes: FC = () => {
|
const Attributes: FC = () => {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
@@ -16,13 +17,17 @@ const Attributes: FC = () => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isModalOpen,
|
isModalOpen,
|
||||||
newAttribute,
|
newAttribute,
|
||||||
|
editingAttributeId,
|
||||||
openModal,
|
openModal,
|
||||||
closeModal,
|
closeModal,
|
||||||
|
openEditModal,
|
||||||
setNewAttribute,
|
setNewAttribute,
|
||||||
addAttribute,
|
addAttribute,
|
||||||
|
deleteAttribute,
|
||||||
addValueToAttribute,
|
addValueToAttribute,
|
||||||
removeValueFromAttribute,
|
removeValueFromAttribute,
|
||||||
isAddingLoading
|
isAddingLoading,
|
||||||
|
isDeletingLoading
|
||||||
} = useAttributesLogic({ id })
|
} = useAttributesLogic({ id })
|
||||||
|
|
||||||
const attributes = attributesData?.results?.data?.category?.attributes || []
|
const attributes = attributesData?.results?.data?.category?.attributes || []
|
||||||
@@ -83,7 +88,7 @@ const Attributes: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen">
|
||||||
<PageTitle />
|
<PageTitle />
|
||||||
<div className="max-w-6xl mx-auto p-6">
|
<div className="max-w-6xl mx-auto p-6">
|
||||||
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
||||||
@@ -157,20 +162,12 @@ const Attributes: FC = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
|
||||||
variant="ghost"
|
<Edit onClick={() => openEditModal(attribute)} color='#8C90A3' size={16} />
|
||||||
size="sm"
|
<TrashWithConfrim
|
||||||
className="text-blue-500 hover:text-blue-700"
|
onDelete={() => deleteAttribute(attribute._id)}
|
||||||
>
|
isLoading={isDeletingLoading}
|
||||||
<Edit size={16} />
|
/>
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="sm"
|
|
||||||
className="text-red-500 hover:text-red-700"
|
|
||||||
>
|
|
||||||
<Trash size={16} />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{attribute.hint && (
|
{attribute.hint && (
|
||||||
@@ -204,6 +201,7 @@ const Attributes: FC = () => {
|
|||||||
onAddValue={addValueToAttribute}
|
onAddValue={addValueToAttribute}
|
||||||
onRemoveValue={removeValueFromAttribute}
|
onRemoveValue={removeValueFromAttribute}
|
||||||
isLoading={isAddingLoading}
|
isLoading={isAddingLoading}
|
||||||
|
isEditing={!!editingAttributeId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ interface AttributesModalProps {
|
|||||||
onAddValue: (text: string) => void
|
onAddValue: (text: string) => void
|
||||||
onRemoveValue: (index: number) => void
|
onRemoveValue: (index: number) => void
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
|
isEditing?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const AttributesModal: FC<AttributesModalProps> = ({
|
const AttributesModal: FC<AttributesModalProps> = ({
|
||||||
@@ -27,7 +28,8 @@ const AttributesModal: FC<AttributesModalProps> = ({
|
|||||||
onAdd,
|
onAdd,
|
||||||
onAddValue,
|
onAddValue,
|
||||||
onRemoveValue,
|
onRemoveValue,
|
||||||
isLoading = false
|
isLoading = false,
|
||||||
|
isEditing = false
|
||||||
}) => {
|
}) => {
|
||||||
const [newValue, setNewValue] = useState('')
|
const [newValue, setNewValue] = useState('')
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ const AttributesModal: FC<AttributesModalProps> = ({
|
|||||||
open={isOpen}
|
open={isOpen}
|
||||||
close={onClose}
|
close={onClose}
|
||||||
isHeader={true}
|
isHeader={true}
|
||||||
title_header="اضافه کردن ویژگی جدید"
|
title_header={isEditing ? "ویرایش ویژگی" : "اضافه کردن ویژگی جدید"}
|
||||||
width={600}
|
width={600}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@@ -150,7 +152,7 @@ const AttributesModal: FC<AttributesModalProps> = ({
|
|||||||
onClick={onAdd}
|
onClick={onAdd}
|
||||||
disabled={!isFormValid() || isLoading}
|
disabled={!isFormValid() || isLoading}
|
||||||
>
|
>
|
||||||
{isLoading ? 'در حال اضافه کردن...' : 'اضافه کردن'}
|
{isLoading ? (isEditing ? 'در حال ویرایش...' : 'در حال اضافه کردن...') : (isEditing ? 'ویرایش' : 'اضافه کردن')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import { useGetCategoryById, useCreateCategoryAttribute } from './useCategoryData'
|
import { useGetCategoryById, useCreateCategoryAttribute, useUpdateCategoryAttribute, useDeleteCategoryAttribute } from './useCategoryData'
|
||||||
import { type CreateCategoryAttributeType } from '../types/Types'
|
import { type CreateCategoryAttributeType } from '../types/Types'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { extractErrorMessage } from '../../../helpers/utils'
|
import { extractErrorMessage } from '../../../helpers/utils'
|
||||||
@@ -13,8 +13,11 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
|
|||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const { data, isLoading } = useGetCategoryById(id!)
|
const { data, isLoading } = useGetCategoryById(id!)
|
||||||
const createAttributeMutation = useCreateCategoryAttribute()
|
const createAttributeMutation = useCreateCategoryAttribute()
|
||||||
|
const updateAttributeMutation = useUpdateCategoryAttribute()
|
||||||
|
const deleteAttributeMutation = useDeleteCategoryAttribute()
|
||||||
|
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||||
|
const [editingAttributeId, setEditingAttributeId] = useState<number | null>(null)
|
||||||
const [newAttribute, setNewAttribute] = useState<CreateCategoryAttributeType>({
|
const [newAttribute, setNewAttribute] = useState<CreateCategoryAttributeType>({
|
||||||
title: '',
|
title: '',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@@ -27,6 +30,7 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
|
|||||||
|
|
||||||
const resetModal = () => {
|
const resetModal = () => {
|
||||||
setIsModalOpen(false)
|
setIsModalOpen(false)
|
||||||
|
setEditingAttributeId(null)
|
||||||
setNewAttribute({
|
setNewAttribute({
|
||||||
title: '',
|
title: '',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@@ -38,23 +42,68 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
|
|||||||
const openModal = () => setIsModalOpen(true)
|
const openModal = () => setIsModalOpen(true)
|
||||||
const closeModal = () => resetModal()
|
const closeModal = () => resetModal()
|
||||||
|
|
||||||
|
const openEditModal = (attribute: any) => {
|
||||||
|
setEditingAttributeId(attribute._id)
|
||||||
|
setNewAttribute({
|
||||||
|
title: attribute.title,
|
||||||
|
type: attribute.type,
|
||||||
|
multiple: attribute.multiple,
|
||||||
|
hint: attribute.hint || '',
|
||||||
|
required: attribute.required,
|
||||||
|
values: attribute.values.map((v: any) => ({ text: v.text }))
|
||||||
|
})
|
||||||
|
setIsModalOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
const addAttribute = async () => {
|
const addAttribute = async () => {
|
||||||
if (!id || !newAttribute.title.trim()) return
|
if (!id || !newAttribute.title.trim()) return
|
||||||
|
|
||||||
createAttributeMutation.mutate(
|
if (editingAttributeId) {
|
||||||
{ id, data: newAttribute },
|
// ویرایش ویژگی
|
||||||
{
|
updateAttributeMutation.mutate(
|
||||||
onSuccess: () => {
|
{ attrId: editingAttributeId, ...newAttribute },
|
||||||
toast.success('ویژگی با موفقیت اضافه شد')
|
{
|
||||||
resetModal()
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['category', id] })
|
toast.success('ویژگی با موفقیت ویرایش شد')
|
||||||
queryClient.invalidateQueries({ queryKey: ['category', 'attributes', id] })
|
resetModal()
|
||||||
},
|
queryClient.invalidateQueries({ queryKey: ['category', id] })
|
||||||
onError: (error) => {
|
queryClient.invalidateQueries({ queryKey: ['category', 'attributes', id] })
|
||||||
toast.error(extractErrorMessage(error))
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(extractErrorMessage(error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// ایجاد ویژگی جدید
|
||||||
|
createAttributeMutation.mutate(
|
||||||
|
{ id, data: newAttribute },
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('ویژگی با موفقیت اضافه شد')
|
||||||
|
resetModal()
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['category', id] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['category', 'attributes', id] })
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(extractErrorMessage(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAttribute = async (attributeId: number) => {
|
||||||
|
deleteAttributeMutation.mutate(attributeId, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('ویژگی با موفقیت حذف شد')
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['category', id] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['category', 'attributes', id] })
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(extractErrorMessage(error))
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateNewAttribute = (field: keyof CreateCategoryAttributeType, value: any) => {
|
const updateNewAttribute = (field: keyof CreateCategoryAttributeType, value: any) => {
|
||||||
@@ -87,16 +136,20 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
|
|||||||
// Modal state
|
// Modal state
|
||||||
isModalOpen,
|
isModalOpen,
|
||||||
newAttribute,
|
newAttribute,
|
||||||
|
editingAttributeId,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
openModal,
|
openModal,
|
||||||
closeModal,
|
closeModal,
|
||||||
|
openEditModal,
|
||||||
setNewAttribute: updateNewAttribute,
|
setNewAttribute: updateNewAttribute,
|
||||||
addAttribute,
|
addAttribute,
|
||||||
|
deleteAttribute,
|
||||||
addValueToAttribute,
|
addValueToAttribute,
|
||||||
removeValueFromAttribute,
|
removeValueFromAttribute,
|
||||||
|
|
||||||
// Loading states
|
// Loading states
|
||||||
isAddingLoading: createAttributeMutation.isPending
|
isAddingLoading: createAttributeMutation.isPending || updateAttributeMutation.isPending,
|
||||||
|
isDeletingLoading: deleteAttributeMutation.isPending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,4 +83,17 @@ export const useGetCategoryAttributes = (id: string) => {
|
|||||||
queryFn: () => api.getCategoryAttributes(id),
|
queryFn: () => api.getCategoryAttributes(id),
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateCategoryAttribute = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (params: CreateCategoryAttributeType & { attrId: number }) =>
|
||||||
|
api.updateCategoryAttribute(params),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteCategoryAttribute = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: number) => api.deleteCategoryAttribute(id),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
@@ -66,4 +66,14 @@ export const createCategoryAttribute = async (id: string, params: CreateCategory
|
|||||||
export const getCategoryAttributes = async (id: string): Promise<CategoryAttributesResponseType> => {
|
export const getCategoryAttributes = async (id: string): Promise<CategoryAttributesResponseType> => {
|
||||||
const { data } = await axios.get(`/category/${id}/attributes`);
|
const { data } = await axios.get(`/category/${id}/attributes`);
|
||||||
return data;
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateCategoryAttribute = async (params: CreateCategoryAttributeType & { attrId: number }) => {
|
||||||
|
const { data } = await axios.patch(`/admin/category/attributes`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteCategoryAttribute = async (id: number) => {
|
||||||
|
const { data } = await axios.delete(`/admin/category/attributes/${id}/delete`);
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user