delete and edit category attribute

This commit is contained in:
hamid zarghami
2025-10-25 15:38:12 +03:30
parent cde35da32a
commit 1683cb9ffe
5 changed files with 110 additions and 34 deletions
+15 -17
View File
@@ -6,7 +6,8 @@ import { AttributesModal } from './components'
import { useAttributesLogic } from './hooks/useAttributesLogic'
import { useGetCategoryAttributes } from './hooks/useCategoryData'
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 { id } = useParams()
@@ -16,13 +17,17 @@ const Attributes: FC = () => {
isLoading,
isModalOpen,
newAttribute,
editingAttributeId,
openModal,
closeModal,
openEditModal,
setNewAttribute,
addAttribute,
deleteAttribute,
addValueToAttribute,
removeValueFromAttribute,
isAddingLoading
isAddingLoading,
isDeletingLoading
} = useAttributesLogic({ id })
const attributes = attributesData?.results?.data?.category?.attributes || []
@@ -83,7 +88,7 @@ const Attributes: FC = () => {
}
return (
<div className="min-h-screen bg-gray-50">
<div className="min-h-screen">
<PageTitle />
<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">
@@ -157,20 +162,12 @@ const Attributes: FC = () => {
)}
</div>
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="sm"
className="text-blue-500 hover:text-blue-700"
>
<Edit size={16} />
</Button>
<Button
variant="ghost"
size="sm"
className="text-red-500 hover:text-red-700"
>
<Trash size={16} />
</Button>
<Edit onClick={() => openEditModal(attribute)} color='#8C90A3' size={16} />
<TrashWithConfrim
onDelete={() => deleteAttribute(attribute._id)}
isLoading={isDeletingLoading}
/>
</div>
</div>
{attribute.hint && (
@@ -204,6 +201,7 @@ const Attributes: FC = () => {
onAddValue={addValueToAttribute}
onRemoveValue={removeValueFromAttribute}
isLoading={isAddingLoading}
isEditing={!!editingAttributeId}
/>
</div>
)
@@ -17,6 +17,7 @@ interface AttributesModalProps {
onAddValue: (text: string) => void
onRemoveValue: (index: number) => void
isLoading?: boolean
isEditing?: boolean
}
const AttributesModal: FC<AttributesModalProps> = ({
@@ -27,7 +28,8 @@ const AttributesModal: FC<AttributesModalProps> = ({
onAdd,
onAddValue,
onRemoveValue,
isLoading = false
isLoading = false,
isEditing = false
}) => {
const [newValue, setNewValue] = useState('')
@@ -55,7 +57,7 @@ const AttributesModal: FC<AttributesModalProps> = ({
open={isOpen}
close={onClose}
isHeader={true}
title_header="اضافه کردن ویژگی جدید"
title_header={isEditing ? "ویرایش ویژگی" : "اضافه کردن ویژگی جدید"}
width={600}
>
<div className="space-y-6">
@@ -150,7 +152,7 @@ const AttributesModal: FC<AttributesModalProps> = ({
onClick={onAdd}
disabled={!isFormValid() || isLoading}
>
{isLoading ? 'در حال اضافه کردن...' : 'اضافه کردن'}
{isLoading ? (isEditing ? 'در حال ویرایش...' : 'در حال اضافه کردن...') : (isEditing ? 'ویرایش' : 'اضافه کردن')}
</Button>
</div>
</div>
+67 -14
View File
@@ -1,6 +1,6 @@
import { useState } from 'react'
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 { toast } from 'react-toastify'
import { extractErrorMessage } from '../../../helpers/utils'
@@ -13,8 +13,11 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
const queryClient = useQueryClient()
const { data, isLoading } = useGetCategoryById(id!)
const createAttributeMutation = useCreateCategoryAttribute()
const updateAttributeMutation = useUpdateCategoryAttribute()
const deleteAttributeMutation = useDeleteCategoryAttribute()
const [isModalOpen, setIsModalOpen] = useState(false)
const [editingAttributeId, setEditingAttributeId] = useState<number | null>(null)
const [newAttribute, setNewAttribute] = useState<CreateCategoryAttributeType>({
title: '',
type: 'text',
@@ -27,6 +30,7 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
const resetModal = () => {
setIsModalOpen(false)
setEditingAttributeId(null)
setNewAttribute({
title: '',
type: 'text',
@@ -38,23 +42,68 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
const openModal = () => setIsModalOpen(true)
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 () => {
if (!id || !newAttribute.title.trim()) return
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))
if (editingAttributeId) {
// ویرایش ویژگی
updateAttributeMutation.mutate(
{ attrId: editingAttributeId, ...newAttribute },
{
onSuccess: () => {
toast.success('ویژگی با موفقیت ویرایش شد')
resetModal()
queryClient.invalidateQueries({ queryKey: ['category', id] })
queryClient.invalidateQueries({ queryKey: ['category', 'attributes', id] })
},
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) => {
@@ -87,16 +136,20 @@ export const useAttributesLogic = ({ id }: UseAttributesLogicProps) => {
// Modal state
isModalOpen,
newAttribute,
editingAttributeId,
// Actions
openModal,
closeModal,
openEditModal,
setNewAttribute: updateNewAttribute,
addAttribute,
deleteAttribute,
addValueToAttribute,
removeValueFromAttribute,
// 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),
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> => {
const { data } = await axios.get(`/category/${id}/attributes`);
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;
};