diff --git a/src/components/renderer/SvgRenderer.tsx b/src/components/renderer/SvgRenderer.tsx index f843e75..b1d3a28 100644 --- a/src/components/renderer/SvgRenderer.tsx +++ b/src/components/renderer/SvgRenderer.tsx @@ -32,7 +32,7 @@ export interface v4OpenAttestationDocument { renderMethod?: RenderMethod[]; } -export type DisplayResult = +export type InternalDisplayResult = | { status: "OK"; svg: string; @@ -46,19 +46,24 @@ export type DisplayResult = } | { status: "DIGEST_ERROR"; + }; + +type PendingImgLoadDisplayResult = { + status: "PENDING_IMG_LOAD"; + svg: string; +}; + +type ResolvedImgLoadDisplayResult = + | { + status: "OK"; + svg: string; } | { status: "INVALID_SVG_ERROR"; svg: string; }; -// this immediate loading state does not need to be exposed -type InternalDisplayResult = - | DisplayResult - | { - status: "PENDING_IMG_LOAD"; - svg: string; - }; +export type DisplayResult = InternalDisplayResult | ResolvedImgLoadDisplayResult; export interface SvgRendererProps { /** The OpenAttestation v4 document to display */ @@ -72,9 +77,6 @@ export interface SvgRendererProps { onResult?: (result: DisplayResult) => void; } -/** Indicates the result of SVG rendering */ -export type DisplayStatusCode = DisplayResult["status"]; - const fetchSvg = async (svgInDoc: string, abortController: AbortController) => { const response = await fetch(svgInDoc, { signal: abortController.signal }); if (!response.ok) { @@ -93,7 +95,9 @@ export const SVG_RENDERER_TYPE = "SvgRenderingTemplate2023"; */ const SvgRenderer = React.forwardRef( ({ document, style, className, onResult }, ref) => { - const [toDisplay, setToDisplay] = useState(null); + const [toDisplay, setToDisplay] = useState< + InternalDisplayResult | PendingImgLoadDisplayResult | ResolvedImgLoadDisplayResult | null + >(null); const renderMethod = document.renderMethod?.find((method) => method.type === SVG_RENDERER_TYPE); const svgInDoc = renderMethod?.id ?? ""; @@ -101,6 +105,17 @@ const SvgRenderer = React.forwardRef( const isSvgUrl = urlPattern.test(svgInDoc); useEffect(() => { + const handleResult = (result: InternalDisplayResult | PendingImgLoadDisplayResult) => { + setToDisplay(result); + + if (onResult) { + // we wait for img load + if (result.status !== "PENDING_IMG_LOAD") { + onResult(result); + } + } + }; + if (!("renderMethod" in document)) { handleResult({ status: "DEFAULT", @@ -159,20 +174,7 @@ const SvgRenderer = React.forwardRef( return () => { abortController.abort(); }; - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - }, [document]); - - const handleResult = (result: InternalDisplayResult) => { - setToDisplay(result); - - if (onResult) { - if (result.status === "PENDING_IMG_LOAD") { - // we wait for img load - } else { - onResult(result); - } - } - }; + }, [document, onResult, isSvgUrl, renderMethod, svgInDoc]); const renderTemplate = (template: string, document: any) => { if (template.length === 0) return ""; @@ -182,6 +184,11 @@ const SvgRenderer = React.forwardRef( if (!toDisplay) return <>; + const handleImgResolved = (resolvedDisplayResult: ResolvedImgLoadDisplayResult) => () => { + setToDisplay(resolvedDisplayResult); + onResult?.(resolvedDisplayResult); + }; + switch (toDisplay.status) { case "INVALID_SVG_ERROR": return ( @@ -209,18 +216,8 @@ const SvgRenderer = React.forwardRef( src={compiledSvgData} ref={ref} alt="Svg image of the verified document" - onLoad={() => { - handleResult({ - status: "OK", - svg: toDisplay.svg, - }); - }} - onError={() => { - handleResult({ - status: "INVALID_SVG_ERROR", - svg: toDisplay.svg, - }); - }} + onLoad={handleImgResolved({ status: "OK", svg: toDisplay.svg })} + onError={handleImgResolved({ status: "INVALID_SVG_ERROR", svg: toDisplay.svg })} /> ); }