Refactor ActionHandler and EditObjectForm components to support forward refs and improve functionality
- Updated ActionHandler to use forwardRef, allowing parent components to access the callAction method. - Enhanced EditObjectForm with forwardRef, enabling external control over editing state and form handling. - Added onEdit and onStateChange props to EditObjectForm for better integration with parent components. - Improved form validation and state management within EditObjectForm, ensuring a smoother user experience. - Cleaned up code for better readability and maintainability.
This commit is contained in:
parent
4201f2b4a3
commit
678d5a0e90
@ -1,15 +1,19 @@
|
|||||||
import React, { useEffect, useRef } from 'react'
|
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
const ActionHandler = ({
|
const ActionHandler = forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
children,
|
children,
|
||||||
actions = {},
|
actions = {},
|
||||||
actionParam = 'action',
|
actionParam = 'action',
|
||||||
clearAfterExecute = true,
|
clearAfterExecute = true,
|
||||||
onAction,
|
onAction,
|
||||||
loading = true
|
loading = true
|
||||||
}) => {
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const action = new URLSearchParams(location.search).get(actionParam)
|
const action = new URLSearchParams(location.search).get(actionParam)
|
||||||
@ -36,6 +40,7 @@ const ActionHandler = ({
|
|||||||
) {
|
) {
|
||||||
// Execute the action
|
// Execute the action
|
||||||
const result = actions[action]()
|
const result = actions[action]()
|
||||||
|
|
||||||
// Mark this action as executed
|
// Mark this action as executed
|
||||||
lastExecutedAction.current = action
|
lastExecutedAction.current = action
|
||||||
// Call optional callback
|
// Call optional callback
|
||||||
@ -66,9 +71,16 @@ const ActionHandler = ({
|
|||||||
navigate
|
navigate
|
||||||
])
|
])
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
callAction
|
||||||
|
}))
|
||||||
|
|
||||||
// Return null as this is a utility component
|
// Return null as this is a utility component
|
||||||
return <>{children({ callAction })}</>
|
return children
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ActionHandler.displayName = 'ActionHandler'
|
||||||
|
|
||||||
ActionHandler.propTypes = {
|
ActionHandler.propTypes = {
|
||||||
children: PropTypes.func,
|
children: PropTypes.func,
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
import React, { useState, useEffect, useContext, useCallback } from 'react'
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useContext,
|
||||||
|
useCallback,
|
||||||
|
forwardRef,
|
||||||
|
useImperativeHandle
|
||||||
|
} 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 { AuthContext } from '../context/AuthContext'
|
||||||
@ -18,7 +25,8 @@ import merge from 'lodash/merge'
|
|||||||
* loading, isEditing, startEditing, cancelEditing, handleUpdate, form, formValid, objectData, setIsEditing, setObjectData
|
* loading, isEditing, startEditing, cancelEditing, handleUpdate, form, formValid, objectData, setIsEditing, setObjectData
|
||||||
* }) => ReactNode
|
* }) => ReactNode
|
||||||
*/
|
*/
|
||||||
const EditObjectForm = ({ id, type, style, children }) => {
|
const EditObjectForm = forwardRef(
|
||||||
|
({ id, type, style, children, onEdit, onStateChange }, ref) => {
|
||||||
const [objectData, setObjectData] = useState(null)
|
const [objectData, setObjectData] = useState(null)
|
||||||
const [serverObjectData, setServerObjectData] = useState(null)
|
const [serverObjectData, setServerObjectData] = useState(null)
|
||||||
const [fetchLoading, setFetchLoading] = useState(true)
|
const [fetchLoading, setFetchLoading] = useState(true)
|
||||||
@ -41,16 +49,22 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
fetchObjectLock,
|
fetchObjectLock,
|
||||||
showError,
|
showError,
|
||||||
connected,
|
connected,
|
||||||
subscribeToObject,
|
subscribeToObjectUpdates,
|
||||||
subscribeToLock
|
subscribeToObjectLock
|
||||||
} = useContext(ApiServerContext)
|
} = useContext(ApiServerContext)
|
||||||
const { token } = useContext(AuthContext)
|
const { token } = useContext(AuthContext)
|
||||||
// Validate form on change
|
// Validate form on change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form
|
form
|
||||||
.validateFields({ validateOnly: true })
|
.validateFields({ validateOnly: true })
|
||||||
.then(() => setFormValid(true))
|
.then(() => {
|
||||||
.catch(() => setFormValid(false))
|
setFormValid(true)
|
||||||
|
onStateChange({ formValid: true })
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setFormValid(false)
|
||||||
|
onStateChange({ formValid: true })
|
||||||
|
})
|
||||||
}, [form, formUpdateValues])
|
}, [form, formUpdateValues])
|
||||||
|
|
||||||
// Cleanup on unmount
|
// Cleanup on unmount
|
||||||
@ -65,13 +79,16 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
const handleFetchObject = useCallback(async () => {
|
const handleFetchObject = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setFetchLoading(true)
|
setFetchLoading(true)
|
||||||
|
onStateChange({ loading: true })
|
||||||
const data = await fetchObject(id, type)
|
const data = await fetchObject(id, type)
|
||||||
const lockEvent = await fetchObjectLock(id, type)
|
const lockEvent = await fetchObjectLock(id, type)
|
||||||
setLock(lockEvent)
|
setLock(lockEvent)
|
||||||
|
onStateChange({ lock: lockEvent })
|
||||||
setObjectData(data)
|
setObjectData(data)
|
||||||
setServerObjectData(data)
|
setServerObjectData(data)
|
||||||
form.setFieldsValue(data)
|
form.setFieldsValue(data)
|
||||||
setFetchLoading(false)
|
setFetchLoading(false)
|
||||||
|
onStateChange({ loading: false })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
messageApi.error('Failed to fetch object info')
|
messageApi.error('Failed to fetch object info')
|
||||||
showError(
|
showError(
|
||||||
@ -88,7 +105,10 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
|
|
||||||
// Update event handler
|
// Update event handler
|
||||||
const updateLockEventHandler = useCallback((value) => {
|
const updateLockEventHandler = useCallback((value) => {
|
||||||
setLock((prev) => ({ ...prev, ...value }))
|
setLock((prev) => {
|
||||||
|
onStateChange({ lock: { ...prev, ...value } })
|
||||||
|
return { ...prev, ...value }
|
||||||
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -100,22 +120,26 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id && connected) {
|
if (id && connected) {
|
||||||
const objectUnsubscribe = subscribeToObject(
|
const objectUpdatesUnsubscribe = subscribeToObjectUpdates(
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
updateObjectEventHandler
|
updateObjectEventHandler
|
||||||
)
|
)
|
||||||
const lockUnsubscribe = subscribeToLock(id, type, updateLockEventHandler)
|
const lockUnsubscribe = subscribeToObjectLock(
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
updateLockEventHandler
|
||||||
|
)
|
||||||
return () => {
|
return () => {
|
||||||
if (objectUnsubscribe) objectUnsubscribe()
|
if (objectUpdatesUnsubscribe) objectUpdatesUnsubscribe()
|
||||||
if (lockUnsubscribe) lockUnsubscribe()
|
if (lockUnsubscribe) lockUnsubscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
subscribeToObject,
|
subscribeToObjectUpdates,
|
||||||
subscribeToLock,
|
subscribeToObjectLock,
|
||||||
updateObjectEventHandler,
|
updateObjectEventHandler,
|
||||||
connected,
|
connected,
|
||||||
updateLockEventHandler
|
updateLockEventHandler
|
||||||
@ -123,6 +147,7 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
|
|
||||||
const startEditing = () => {
|
const startEditing = () => {
|
||||||
setIsEditing(true)
|
setIsEditing(true)
|
||||||
|
onStateChange({ isEditing: true })
|
||||||
lockObject(id, type)
|
lockObject(id, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +157,7 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
setObjectData(serverObjectData)
|
setObjectData(serverObjectData)
|
||||||
}
|
}
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
|
onStateChange({ isEditing: false })
|
||||||
unlockObject(id, type)
|
unlockObject(id, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,9 +165,11 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
try {
|
try {
|
||||||
const value = await form.validateFields()
|
const value = await form.validateFields()
|
||||||
setEditLoading(true)
|
setEditLoading(true)
|
||||||
|
onStateChange({ editLoading: true })
|
||||||
await updateObject(id, type, value)
|
await updateObject(id, type, value)
|
||||||
setObjectData({ ...objectData, ...value })
|
setObjectData({ ...objectData, ...value })
|
||||||
setIsEditing(false)
|
setIsEditing(false)
|
||||||
|
onStateChange({ isEditing: false })
|
||||||
messageApi.success('Information updated successfully')
|
messageApi.success('Information updated successfully')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.errorFields) {
|
if (err.errorFields) {
|
||||||
@ -155,6 +183,7 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
} finally {
|
} finally {
|
||||||
handleFetchObject()
|
handleFetchObject()
|
||||||
setEditLoading(false)
|
setEditLoading(false)
|
||||||
|
onStateChange({ editLoading: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +209,20 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
startEditing,
|
||||||
|
cancelEditing,
|
||||||
|
handleUpdate,
|
||||||
|
handleDelete,
|
||||||
|
confirmDelete,
|
||||||
|
handleFetchObject,
|
||||||
|
editLoading,
|
||||||
|
fetchLoading,
|
||||||
|
isEditing,
|
||||||
|
objectData,
|
||||||
|
lock
|
||||||
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DeleteObjectModal
|
<DeleteObjectModal
|
||||||
@ -195,7 +238,12 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
layout='vertical'
|
layout='vertical'
|
||||||
style={style}
|
style={style}
|
||||||
onValuesChange={(values) => {
|
onValuesChange={(values) => {
|
||||||
setObjectData((prev) => ({ ...prev, ...values }))
|
if (onEdit != undefined) {
|
||||||
|
onEdit(values)
|
||||||
|
}
|
||||||
|
setObjectData((prev) => {
|
||||||
|
return { ...prev, ...values }
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@ -218,13 +266,18 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
</Form>
|
</Form>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
EditObjectForm.displayName = 'EditObjectForm'
|
||||||
|
|
||||||
EditObjectForm.propTypes = {
|
EditObjectForm.propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
type: PropTypes.string.isRequired,
|
type: PropTypes.string.isRequired,
|
||||||
children: PropTypes.func.isRequired,
|
children: PropTypes.func.isRequired,
|
||||||
style: PropTypes.object
|
style: PropTypes.object,
|
||||||
|
onEdit: PropTypes.func,
|
||||||
|
onStateChange: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EditObjectForm
|
export default EditObjectForm
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user