From c0e3c6239a0e24f500c74c4cff79b57785e5e777 Mon Sep 17 00:00:00 2001 From: mrica-equinor Date: Mon, 18 May 2026 08:36:34 +0200 Subject: [PATCH 1/2] Fix invalid hook error --- .../Contexts/InspectionsContext.tsx | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Contexts/InspectionsContext.tsx b/frontend/src/components/Contexts/InspectionsContext.tsx index 185294110..fff031b47 100644 --- a/frontend/src/components/Contexts/InspectionsContext.tsx +++ b/frontend/src/components/Contexts/InspectionsContext.tsx @@ -1,4 +1,4 @@ -import { createContext, FC, useContext, useEffect } from 'react' +import { createContext, FC, useContext, useEffect, useRef } from 'react' import { SignalREventLabels, useSignalRContext } from './SignalRContext' import { SaraAnalysisResultReady, SaraInspectionVisualizationReady } from 'models/Inspection' import { useQuery } from '@tanstack/react-query' @@ -37,14 +37,29 @@ export const InspectionsProvider: FC = ({ children }) => { const { registerEvent, connectionReady } = useSignalRContext() const backendApi = useBackendApi() + // Keep a stable ref to backendApi so callbacks don't capture a stale closure + const backendApiRef = useRef(backendApi) + useEffect(() => { + backendApiRef.current = backendApi + }, [backendApi]) + useEffect(() => { if (connectionReady) { registerEvent(SignalREventLabels.inspectionVisualizationReady, (username: string, message: string) => { const inspectionVisualizationData: SaraInspectionVisualizationReady = JSON.parse(message) + const inspectionId = inspectionVisualizationData.inspectionId queryClient.invalidateQueries({ - queryKey: ['fetchInspectionData', inspectionVisualizationData.inspectionId], + queryKey: ['fetchInspectionData', inspectionId], + }) + queryClient.fetchQuery({ + queryKey: ['fetchInspectionData', inspectionId], + queryFn: async () => { + const imageBlob = await backendApiRef.current.getInspection(inspectionId) + return URL.createObjectURL(imageBlob) + }, + retry: 1, + staleTime: 10 * 60 * 1000, }) - fetchImageData(inspectionVisualizationData.inspectionId) }) } }, [registerEvent, connectionReady]) @@ -53,10 +68,19 @@ export const InspectionsProvider: FC = ({ children }) => { if (connectionReady) { registerEvent(SignalREventLabels.analysisResultReady, (username: string, message: string) => { const analysisResultData: SaraAnalysisResultReady = JSON.parse(message) + const inspectionId = analysisResultData.inspectionId queryClient.invalidateQueries({ - queryKey: ['fetchAnalysisData', analysisResultData.inspectionId], + queryKey: ['fetchAnalysisData', inspectionId], + }) + queryClient.fetchQuery({ + queryKey: ['fetchAnalysisData', inspectionId], + queryFn: async () => { + const imageBlob = await backendApiRef.current.getAnalysis(inspectionId) + return URL.createObjectURL(imageBlob) + }, + retry: 1, + staleTime: 10 * 60 * 1000, }) - fetchAnalysisData(analysisResultData.inspectionId) }) } }, [registerEvent, connectionReady]) From 3df228448acd5eb2ffddbb43faf3d98f60d3b4eb Mon Sep 17 00:00:00 2001 From: mrica-equinor Date: Mon, 18 May 2026 08:56:30 +0200 Subject: [PATCH 2/2] Rename fetch functions to use hooks --- .../Contexts/InspectionsContext.tsx | 27 +++++++++---------- .../InspectionReportImage.tsx | 8 +++--- .../pages/MissionPage/AnalysisResultView.tsx | 4 +-- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/Contexts/InspectionsContext.tsx b/frontend/src/components/Contexts/InspectionsContext.tsx index fff031b47..16e8b9dc6 100644 --- a/frontend/src/components/Contexts/InspectionsContext.tsx +++ b/frontend/src/components/Contexts/InspectionsContext.tsx @@ -16,9 +16,9 @@ interface IValueData { isError: boolean } interface IInspectionsContext { - fetchImageData: (inspectionId: string) => IImageData - fetchAnalysisData: (inspectionId: string) => IImageData - fetchValueData: (inspectionId: string) => IValueData + useImageData: (inspectionId: string) => IImageData + useAnalysisData: (inspectionId: string) => IImageData + useValueData: (inspectionId: string) => IValueData } interface Props { @@ -26,9 +26,9 @@ interface Props { } const defaultInspectionsContext = { - fetchImageData: () => ({ data: undefined, isPending: false, isError: true }), - fetchAnalysisData: () => ({ data: undefined, isPending: false, isError: true }), - fetchValueData: () => ({ data: undefined, isPending: false, isError: true }), + useImageData: () => ({ data: undefined, isPending: false, isError: true }), + useAnalysisData: () => ({ data: undefined, isPending: false, isError: true }), + useValueData: () => ({ data: undefined, isPending: false, isError: true }), } const InspectionsContext = createContext(defaultInspectionsContext) @@ -85,8 +85,7 @@ export const InspectionsProvider: FC = ({ children }) => { } }, [registerEvent, connectionReady]) - const fetchImageData = (inspectionId: string): IImageData => { - // eslint-disable-next-line react-hooks/rules-of-hooks -- pre-existing design issue, tracked in #2698 + const useImageData = (inspectionId: string): IImageData => { const result = useQuery({ queryKey: ['fetchInspectionData', inspectionId], queryFn: async () => { @@ -101,8 +100,7 @@ export const InspectionsProvider: FC = ({ children }) => { return { data: result.data, isPending: result.isPending, isError: result.isError } } - const fetchAnalysisData = (inspectionId: string): IImageData => { - // eslint-disable-next-line react-hooks/rules-of-hooks -- pre-existing design issue, tracked in #2698 + const useAnalysisData = (inspectionId: string): IImageData => { const result = useQuery({ queryKey: ['fetchAnalysisData', inspectionId], queryFn: async () => { @@ -116,8 +114,7 @@ export const InspectionsProvider: FC = ({ children }) => { return { data: result.data, isPending: result.isPending, isError: result.isError } } - const fetchValueData = (inspectionId: string): IValueData => { - // eslint-disable-next-line react-hooks/rules-of-hooks -- pre-existing design issue, tracked in #2698 + const useValueData = (inspectionId: string): IValueData => { const result = useQuery({ queryKey: ['fetchValueData', inspectionId], queryFn: async () => { @@ -134,9 +131,9 @@ export const InspectionsProvider: FC = ({ children }) => { return ( {children} diff --git a/frontend/src/pages/InspectionReportPage/InspectionReportImage.tsx b/frontend/src/pages/InspectionReportPage/InspectionReportImage.tsx index e60747ca9..51c2b2b84 100644 --- a/frontend/src/pages/InspectionReportPage/InspectionReportImage.tsx +++ b/frontend/src/pages/InspectionReportPage/InspectionReportImage.tsx @@ -81,8 +81,8 @@ export const PendingResultPlaceholder = ({ isLargeImage }: { isLargeImage: boole } const InspectionImageWithPlaceholder = ({ task, isLargeImage }: { task: Task; isLargeImage: boolean }) => { - const { fetchImageData } = useInspectionsContext() - const { data, isPending, isError } = fetchImageData(task.inspection.isarInspectionId) + const { useImageData } = useInspectionsContext() + const { data, isPending, isError } = useImageData(task.inspection.isarInspectionId) if (isError || !data) { const errorMsg = 'No inspection could be found' return @@ -97,8 +97,8 @@ const InspectionImageWithPlaceholder = ({ task, isLargeImage }: { task: Task; is } const InspectionValueWithPlaceholder = ({ task, isLargeImage }: { task: Task; isLargeImage: boolean }) => { - const { fetchValueData } = useInspectionsContext() - const { data, isPending, isError } = fetchValueData(task.inspection.isarInspectionId) + const { useValueData } = useInspectionsContext() + const { data, isPending, isError } = useValueData(task.inspection.isarInspectionId) if (isError || data === undefined) { const errorMsg = 'No inspection could be found' diff --git a/frontend/src/pages/MissionPage/AnalysisResultView.tsx b/frontend/src/pages/MissionPage/AnalysisResultView.tsx index c2f4ed7ee..9a29701c0 100644 --- a/frontend/src/pages/MissionPage/AnalysisResultView.tsx +++ b/frontend/src/pages/MissionPage/AnalysisResultView.tsx @@ -27,8 +27,8 @@ const StyledImage = styled.img<{ $otherContentHeight?: string }>` border: none; ` const AnalysisImage = ({ inspectionId }: { inspectionId: string }) => { - const { fetchAnalysisData } = useInspectionsContext() - const { data, isPending } = fetchAnalysisData(inspectionId) + const { useAnalysisData } = useInspectionsContext() + const { data, isPending } = useAnalysisData(inspectionId) if (isPending) return if (!data) return