Refactor TemplateEditor and TemplatePreview components for improved performance and error handling
Some checks failed
farmcontrol/farmcontrol-ui/pipeline/head There was a failure building this commit

- Updated TemplateEditor to use useCallback for handlePreviewMessage, optimizing performance.
- Enhanced TemplatePreview by adding default no-op functions for onTestObjectOpen and onPreviewMessage props.
- Improved error handling in fetchTemplatePDF and fetchTemplatePreview methods to ensure callbacks are only invoked if they are functions.
- Refactored preview loading logic to prevent unnecessary calls when template ID is not available.
This commit is contained in:
Tom Butcher 2026-07-28 01:50:16 +01:00
parent 59d16f80aa
commit f743f9b892
3 changed files with 52 additions and 15 deletions

View File

@ -1,4 +1,4 @@
import { useState } from 'react'
import { useState, useCallback } from 'react'
import PropTypes from 'prop-types'
import {
Flex,
@ -31,10 +31,10 @@ const TemplateEditor = ({
const [previewError, setPreviewError] = useState(false)
//const isMobile = useMediaQuery({ maxWidth: 768 })
const handlePreviewMessage = (message, isError) => {
const handlePreviewMessage = useCallback((message, isError) => {
setPreviewMessage(message)
setPreviewError(isError)
}
}, [])
return (
<>

View File

@ -7,17 +7,20 @@ import InfoCircleIcon from '../../Icons/InfoCircleIcon.jsx'
import ObjectProperty from '../common/ObjectProperty.jsx'
import { ApiServerContext } from '../context/ApiServerContext.jsx'
const noop = () => {}
const TemplatePreview = ({
objectData,
documentTemplate,
loading,
isEditing,
onTestObjectOpen,
onPreviewMessage,
onTestObjectOpen = noop,
onPreviewMessage = noop,
showTestObject = false,
showPreviewSwitch = true
}) => {
const iframeRef = useRef(null)
const previewRequestIdRef = useRef(0)
const { fetchTemplatePreview, fetchTemplatePDF } =
useContext(ApiServerContext)
const [previewContentHTML, setPreviewContentHTML] = useState('')
@ -46,11 +49,19 @@ const TemplatePreview = ({
const reloadPreviewPDF = useCallback(
(content, testObject = {}) => {
const templateId = documentTemplate?._id
if (!templateId) {
return
}
const requestId = ++previewRequestIdRef.current
setReloadLoading(true)
fetchTemplatePDF(documentTemplate._id, content, testObject, (result) => {
fetchTemplatePDF(templateId, content, testObject, (result) => {
if (requestId !== previewRequestIdRef.current) {
return
}
setReloadLoading(false)
if (result?.error) {
// Handle error through parent component
onPreviewMessage(result.error, true)
} else {
const pdfBlob = new Blob([result.pdf], { type: 'application/pdf' })
@ -66,16 +77,24 @@ const TemplatePreview = ({
const reloadPreview = useCallback(
(content, testObject = {}, scale = 1) => {
const templateId = documentTemplate?._id
if (!templateId) {
return
}
const requestId = ++previewRequestIdRef.current
setReloadLoading(true)
fetchTemplatePreview(
documentTemplate._id,
templateId,
content,
testObject,
scale,
(result) => {
if (requestId !== previewRequestIdRef.current) {
return
}
setReloadLoading(false)
if (result?.error) {
// Handle error through parent component
onPreviewMessage(result.error, true)
} else {
updatePreviewContentHTML(result.html)
@ -87,18 +106,30 @@ const TemplatePreview = ({
[fetchTemplatePreview, onPreviewMessage, documentTemplate?._id]
)
const templateContent = documentTemplate?.content
const templateId = documentTemplate?._id
// Move useEffect to component level and use state to track objectData changes
useEffect(() => {
if (documentTemplate?.content) {
if (previewType == 'HTML') {
reloadPreview(documentTemplate.content, objectData, previewScale)
} else {
reloadPreviewPDF(documentTemplate.content, objectData)
if (!templateId || !templateContent) {
return
}
const timeoutId = window.setTimeout(() => {
if (previewType == 'HTML') {
reloadPreview(templateContent, objectData, previewScale)
} else {
reloadPreviewPDF(templateContent, objectData)
}
}, 300)
return () => {
window.clearTimeout(timeoutId)
}
}, [
objectData,
documentTemplate,
templateContent,
templateId,
previewScale,
previewType,
reloadPreview,
@ -197,8 +228,8 @@ TemplatePreview.propTypes = {
isEditing: PropTypes.bool,
style: PropTypes.object,
showTestObject: PropTypes.bool,
onTestObjectOpen: PropTypes.func.isRequired,
onPreviewMessage: PropTypes.func.isRequired,
onTestObjectOpen: PropTypes.func,
onPreviewMessage: PropTypes.func,
showPreviewSwitch: PropTypes.bool
}

View File

@ -1691,6 +1691,9 @@ const ApiServerProvider = ({ children }) => {
callback
)
}
if (typeof callback === 'function') {
callback({ error: 'Api Server disconnected' })
}
}
const fetchTemplatePDF = async (id, content, testObject, callback) => {
@ -1706,6 +1709,9 @@ const ApiServerProvider = ({ children }) => {
callback
)
}
if (typeof callback === 'function') {
callback({ error: 'Api Server disconnected' })
}
}
const downloadTemplatePDF = async (