diff --git a/src/components/Dashboard/Management/Vendors/VendorInfo.jsx b/src/components/Dashboard/Management/Vendors/VendorInfo.jsx index 1b2ebe2..d04784d 100644 --- a/src/components/Dashboard/Management/Vendors/VendorInfo.jsx +++ b/src/components/Dashboard/Management/Vendors/VendorInfo.jsx @@ -42,17 +42,18 @@ const VendorInfo = () => { isEditing, startEditing, cancelEditing, + handleFetchObject, handleUpdate, + handleDelete, formValid, objectData, editLoading, - lock, - fetchObject + lock }) => { // Define actions for ActionHandler const actions = { reload: () => { - fetchObject() + handleFetchObject() return true }, edit: () => { @@ -66,6 +67,10 @@ const VendorInfo = () => { finishEdit: () => { handleUpdate() return true + }, + delete: () => { + handleDelete() + return true } } @@ -127,7 +132,7 @@ const VendorInfo = () => { onToggle={(expanded) => updateCollapseState('info', expanded) } - key='info' + collapseKey='info' > { onToggle={(expanded) => updateCollapseState('notes', expanded) } - key='notes' + collapseKey='notes' > - + @@ -158,7 +163,7 @@ const VendorInfo = () => { onToggle={(expanded) => updateCollapseState('auditLogs', expanded) } - key='auditLogs' + collapseKey='auditLogs' > {loading ? ( diff --git a/src/components/Dashboard/common/EditObjectForm.jsx b/src/components/Dashboard/common/EditObjectForm.jsx index 4f4cda0..e3e8835 100644 --- a/src/components/Dashboard/common/EditObjectForm.jsx +++ b/src/components/Dashboard/common/EditObjectForm.jsx @@ -1,7 +1,9 @@ import React, { useState, useEffect, useContext, useCallback } from 'react' import { Form, message } from 'antd' import { ApiServerContext } from '../context/ApiServerContext' +import { AuthContext } from '../context/AuthContext' import PropTypes from 'prop-types' +import DeleteObjectModal from './DeleteObjectModal' /** * 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 formUpdateValues = Form.useWatch([], form) const [messageApi, contextHolder] = message.useMessage() + const [deleteModalOpen, setDeleteModalOpen] = useState(false) + const [deleteLoading, setDeleteLoading] = useState(false) const { - fetchObjectInfo, - updateObjectInfo, + fetchObject, + updateObject, + deleteObject, lockObject, unlockObject, - onLockEvent, - onUpdateEvent, fetchObjectLock, - showError + showError, + connected, + subscribeToObject, + subscribeToLock } = useContext(ApiServerContext) - + const { authenticated } = useContext(AuthContext) // Validate form on change useEffect(() => { form @@ -46,11 +52,6 @@ const EditObjectForm = ({ id, type, style, children }) => { .catch(() => setFormValid(false)) }, [form, formUpdateValues]) - // Lock event handler - const lockEventHandler = useCallback((lockEvent) => { - setLock(lockEvent) - }, []) - // Cleanup on unmount useEffect(() => { return () => { @@ -60,10 +61,10 @@ const EditObjectForm = ({ id, type, style, children }) => { } }, [id, type, unlockObject]) - const fetchObject = useCallback(async () => { + const handleFetchObject = useCallback(async () => { try { setFetchLoading(true) - const data = await fetchObjectInfo(id, type) + const data = await fetchObject(id, type) const lockEvent = await fetchObjectLock(id, type) setLock(lockEvent) setObjectData(data) @@ -77,38 +78,47 @@ const EditObjectForm = ({ id, type, style, children }) => { fetchObject ) } - }, [fetchObjectInfo, fetchObjectLock, id, type, form, messageApi, showError]) - - const updateObject = async () => { - const values = form.getFieldsValue() - await updateObjectInfo(id, type, values) - } + }, [fetchObject, fetchObjectLock, id, type, form, messageApi, showError]) // Update event handler - const updateEventHandler = useCallback(() => { - fetchObject() - }, [fetchObject]) + const updateObjectEventHandler = useCallback((value) => { + setObjectData((prev) => ({ ...prev, ...value })) + }, []) + + // Update event handler + const updateLockEventHandler = useCallback((value) => { + setLock((prev) => ({ ...prev, ...value })) + }, []) useEffect(() => { - if (!initialized && id) { + if (!initialized && id && authenticated == true) { setInitialized(true) - fetchObject() + handleFetchObject() } - }, [id, initialized, fetchObject]) + }, [id, initialized, handleFetchObject, authenticated]) useEffect(() => { - if (id) { - const cleanup = onLockEvent(id, lockEventHandler) - return cleanup + if (id && connected) { + const objectUnsubscribe = subscribeToObject( + id, + type, + updateObjectEventHandler + ) + const lockUnsubscribe = subscribeToLock(id, type, updateLockEventHandler) + return () => { + if (objectUnsubscribe) objectUnsubscribe() + if (lockUnsubscribe) lockUnsubscribe() + } } - }, [id, onLockEvent, lockEventHandler]) - - useEffect(() => { - if (id) { - const cleanup = onUpdateEvent(id, updateEventHandler) - return cleanup - } - }, [id, onUpdateEvent, updateEventHandler]) + }, [ + id, + type, + subscribeToObject, + subscribeToLock, + updateObjectEventHandler, + connected, + updateLockEventHandler + ]) const startEditing = () => { setIsEditing(true) @@ -126,10 +136,10 @@ const EditObjectForm = ({ id, type, style, children }) => { const handleUpdate = async () => { try { - const values = await form.validateFields() + const value = await form.validateFields() setEditLoading(true) - await updateObject() - setObjectData({ ...objectData, ...values }) + await updateObject(id, type, value) + setObjectData({ ...objectData, ...value }) setIsEditing(false) messageApi.success('Information updated successfully') } catch (err) { @@ -142,37 +152,70 @@ const EditObjectForm = ({ id, type, style, children }) => { () => handleUpdate() ) } finally { - fetchObject() + handleFetchObject() 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 ( -
{ - setObjectData((prev) => ({ ...prev, ...values })) - }} - > - {contextHolder} - {children({ - loading: fetchLoading, - isEditing, - startEditing, - cancelEditing, - handleUpdate, - form, - formValid, - objectData, - setIsEditing, - setObjectData, - editLoading, - lock, - fetchObject - })} -
+ <> + setDeleteModalOpen(false)} + loading={deleteLoading} + objectType={type} + objectName={objectData?.name || objectData?.label || ''} + /> +
{ + setObjectData((prev) => ({ ...prev, ...values })) + }} + > + {contextHolder} + {children({ + loading: fetchLoading, + isEditing, + startEditing, + cancelEditing, + handleUpdate, + form, + formValid, + objectData, + setIsEditing, + setObjectData, + editLoading, + lock, + handleFetchObject, + handleDelete + })} +
+ ) } diff --git a/src/database/models/Vendor.js b/src/database/models/Vendor.js index b38c2f0..915ceaf 100644 --- a/src/database/models/Vendor.js +++ b/src/database/models/Vendor.js @@ -2,6 +2,7 @@ import VendorIcon from '../../components/Icons/VendorIcon' import InfoCircleIcon from '../../components/Icons/InfoCircleIcon' import EditIcon from '../../components/Icons/EditIcon' import ReloadIcon from '../../components/Icons/ReloadIcon' +import BinIcon from '../../components/Icons/BinIcon' export const Vendor = { name: 'vendor', @@ -31,6 +32,15 @@ export const Vendor = { icon: EditIcon, url: (_id) => `/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}`,