Added delete functionality

This commit is contained in:
Tom Butcher 2025-07-14 22:58:12 +01:00
parent 528d8d1259
commit 4788b76363
3 changed files with 130 additions and 72 deletions

View File

@ -42,17 +42,18 @@ const VendorInfo = () => {
isEditing, isEditing,
startEditing, startEditing,
cancelEditing, cancelEditing,
handleFetchObject,
handleUpdate, handleUpdate,
handleDelete,
formValid, formValid,
objectData, objectData,
editLoading, editLoading,
lock, lock
fetchObject
}) => { }) => {
// Define actions for ActionHandler // Define actions for ActionHandler
const actions = { const actions = {
reload: () => { reload: () => {
fetchObject() handleFetchObject()
return true return true
}, },
edit: () => { edit: () => {
@ -66,6 +67,10 @@ const VendorInfo = () => {
finishEdit: () => { finishEdit: () => {
handleUpdate() handleUpdate()
return true return true
},
delete: () => {
handleDelete()
return true
} }
} }
@ -127,7 +132,7 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('info', expanded)
} }
key='info' collapseKey='info'
> >
<ObjectInfo <ObjectInfo
loading={loading} loading={loading}
@ -144,10 +149,10 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('notes', expanded) updateCollapseState('notes', expanded)
} }
key='notes' collapseKey='notes'
> >
<Card> <Card>
<NotesPanel _id={vendorId} /> <NotesPanel _id={vendorId} type='vendor' />
</Card> </Card>
</InfoCollapse> </InfoCollapse>
@ -158,7 +163,7 @@ const VendorInfo = () => {
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded) updateCollapseState('auditLogs', expanded)
} }
key='auditLogs' collapseKey='auditLogs'
> >
{loading ? ( {loading ? (
<InfoCollapsePlaceholder /> <InfoCollapsePlaceholder />

View File

@ -1,7 +1,9 @@
import React, { useState, useEffect, useContext, useCallback } from 'react' import React, { useState, useEffect, useContext, useCallback } from 'react'
import { Form, message } from 'antd' import { Form, message } from 'antd'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
import { AuthContext } from '../context/AuthContext'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import DeleteObjectModal from './DeleteObjectModal'
/** /**
* EditObjectForm is a reusable form component for editing any object type. * EditObjectForm is a reusable form component for editing any object type.
@ -27,17 +29,21 @@ const EditObjectForm = ({ id, type, style, children }) => {
const [form] = Form.useForm() const [form] = Form.useForm()
const formUpdateValues = Form.useWatch([], form) const formUpdateValues = Form.useWatch([], form)
const [messageApi, contextHolder] = message.useMessage() const [messageApi, contextHolder] = message.useMessage()
const [deleteModalOpen, setDeleteModalOpen] = useState(false)
const [deleteLoading, setDeleteLoading] = useState(false)
const { const {
fetchObjectInfo, fetchObject,
updateObjectInfo, updateObject,
deleteObject,
lockObject, lockObject,
unlockObject, unlockObject,
onLockEvent,
onUpdateEvent,
fetchObjectLock, fetchObjectLock,
showError showError,
connected,
subscribeToObject,
subscribeToLock
} = useContext(ApiServerContext) } = useContext(ApiServerContext)
const { authenticated } = useContext(AuthContext)
// Validate form on change // Validate form on change
useEffect(() => { useEffect(() => {
form form
@ -46,11 +52,6 @@ const EditObjectForm = ({ id, type, style, children }) => {
.catch(() => setFormValid(false)) .catch(() => setFormValid(false))
}, [form, formUpdateValues]) }, [form, formUpdateValues])
// Lock event handler
const lockEventHandler = useCallback((lockEvent) => {
setLock(lockEvent)
}, [])
// Cleanup on unmount // Cleanup on unmount
useEffect(() => { useEffect(() => {
return () => { return () => {
@ -60,10 +61,10 @@ const EditObjectForm = ({ id, type, style, children }) => {
} }
}, [id, type, unlockObject]) }, [id, type, unlockObject])
const fetchObject = useCallback(async () => { const handleFetchObject = useCallback(async () => {
try { try {
setFetchLoading(true) setFetchLoading(true)
const data = await fetchObjectInfo(id, type) const data = await fetchObject(id, type)
const lockEvent = await fetchObjectLock(id, type) const lockEvent = await fetchObjectLock(id, type)
setLock(lockEvent) setLock(lockEvent)
setObjectData(data) setObjectData(data)
@ -77,38 +78,47 @@ const EditObjectForm = ({ id, type, style, children }) => {
fetchObject fetchObject
) )
} }
}, [fetchObjectInfo, fetchObjectLock, id, type, form, messageApi, showError]) }, [fetchObject, fetchObjectLock, id, type, form, messageApi, showError])
const updateObject = async () => {
const values = form.getFieldsValue()
await updateObjectInfo(id, type, values)
}
// Update event handler // Update event handler
const updateEventHandler = useCallback(() => { const updateObjectEventHandler = useCallback((value) => {
fetchObject() setObjectData((prev) => ({ ...prev, ...value }))
}, [fetchObject]) }, [])
// Update event handler
const updateLockEventHandler = useCallback((value) => {
setLock((prev) => ({ ...prev, ...value }))
}, [])
useEffect(() => { useEffect(() => {
if (!initialized && id) { if (!initialized && id && authenticated == true) {
setInitialized(true) setInitialized(true)
fetchObject() handleFetchObject()
} }
}, [id, initialized, fetchObject]) }, [id, initialized, handleFetchObject, authenticated])
useEffect(() => { useEffect(() => {
if (id) { if (id && connected) {
const cleanup = onLockEvent(id, lockEventHandler) const objectUnsubscribe = subscribeToObject(
return cleanup id,
type,
updateObjectEventHandler
)
const lockUnsubscribe = subscribeToLock(id, type, updateLockEventHandler)
return () => {
if (objectUnsubscribe) objectUnsubscribe()
if (lockUnsubscribe) lockUnsubscribe()
}
} }
}, [id, onLockEvent, lockEventHandler]) }, [
id,
useEffect(() => { type,
if (id) { subscribeToObject,
const cleanup = onUpdateEvent(id, updateEventHandler) subscribeToLock,
return cleanup updateObjectEventHandler,
} connected,
}, [id, onUpdateEvent, updateEventHandler]) updateLockEventHandler
])
const startEditing = () => { const startEditing = () => {
setIsEditing(true) setIsEditing(true)
@ -126,10 +136,10 @@ const EditObjectForm = ({ id, type, style, children }) => {
const handleUpdate = async () => { const handleUpdate = async () => {
try { try {
const values = await form.validateFields() const value = await form.validateFields()
setEditLoading(true) setEditLoading(true)
await updateObject() await updateObject(id, type, value)
setObjectData({ ...objectData, ...values }) setObjectData({ ...objectData, ...value })
setIsEditing(false) setIsEditing(false)
messageApi.success('Information updated successfully') messageApi.success('Information updated successfully')
} catch (err) { } catch (err) {
@ -142,37 +152,70 @@ const EditObjectForm = ({ id, type, style, children }) => {
() => handleUpdate() () => handleUpdate()
) )
} finally { } finally {
fetchObject() handleFetchObject()
setEditLoading(false) setEditLoading(false)
} }
} }
const handleDelete = () => {
setDeleteModalOpen(true)
}
const confirmDelete = async () => {
setDeleteLoading(true)
try {
await deleteObject(id, type)
setDeleteModalOpen(false)
messageApi.success('Deleted successfully')
// Optionally: trigger a callback to parent to remove this object from view
} catch (err) {
messageApi.error('Failed to delete')
showError(
`Failed to delete. Message: ${err.message}. Code: ${err.code}`,
confirmDelete
)
} finally {
setDeleteLoading(false)
}
}
return ( return (
<Form <>
form={form} <DeleteObjectModal
layout='vertical' open={deleteModalOpen}
style={style} onOk={confirmDelete}
onValuesChange={(values) => { onCancel={() => setDeleteModalOpen(false)}
setObjectData((prev) => ({ ...prev, ...values })) loading={deleteLoading}
}} objectType={type}
> objectName={objectData?.name || objectData?.label || ''}
{contextHolder} />
{children({ <Form
loading: fetchLoading, form={form}
isEditing, layout='vertical'
startEditing, style={style}
cancelEditing, onValuesChange={(values) => {
handleUpdate, setObjectData((prev) => ({ ...prev, ...values }))
form, }}
formValid, >
objectData, {contextHolder}
setIsEditing, {children({
setObjectData, loading: fetchLoading,
editLoading, isEditing,
lock, startEditing,
fetchObject cancelEditing,
})} handleUpdate,
</Form> form,
formValid,
objectData,
setIsEditing,
setObjectData,
editLoading,
lock,
handleFetchObject,
handleDelete
})}
</Form>
</>
) )
} }

View File

@ -2,6 +2,7 @@ import VendorIcon from '../../components/Icons/VendorIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon' import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import EditIcon from '../../components/Icons/EditIcon' import EditIcon from '../../components/Icons/EditIcon'
import ReloadIcon from '../../components/Icons/ReloadIcon' import ReloadIcon from '../../components/Icons/ReloadIcon'
import BinIcon from '../../components/Icons/BinIcon'
export const Vendor = { export const Vendor = {
name: 'vendor', name: 'vendor',
@ -31,6 +32,15 @@ export const Vendor = {
icon: EditIcon, icon: EditIcon,
url: (_id) => url: (_id) =>
`/dashboard/management/vendors/info?vendorId=${_id}&action=edit` `/dashboard/management/vendors/info?vendorId=${_id}&action=edit`
},
{ type: 'divider' },
{
name: 'delete',
label: 'Delete',
icon: BinIcon,
danger: true,
url: (_id) =>
`/dashboard/management/vendors/info?vendorId=${_id}&action=delete`
} }
], ],
url: (id) => `/dashboard/management/vendors/info?vendorId=${id}`, url: (id) => `/dashboard/management/vendors/info?vendorId=${id}`,