From e9e19fbd9f04d1388b7c7da660ada71e672b43cd Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Wed, 11 Mar 2026 14:01:33 +0000 Subject: [PATCH] Load API images via authenticated fetch instead of bare img src img tags don't send Authorization headers; AuthImage component fetches via axios (with Bearer token) and renders a blob URL. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/AuthImage.tsx | 24 ++++++++++++++++++++++++ frontend/src/pages/AnalysisView.tsx | 3 ++- frontend/src/pages/ComparisonView.tsx | 3 ++- frontend/src/pages/ProjectDetail.tsx | 6 ++---- 4 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 frontend/src/components/AuthImage.tsx diff --git a/frontend/src/components/AuthImage.tsx b/frontend/src/components/AuthImage.tsx new file mode 100644 index 0000000..e3e7142 --- /dev/null +++ b/frontend/src/components/AuthImage.tsx @@ -0,0 +1,24 @@ +import { useEffect, useState, ImgHTMLAttributes } from "react"; +import client from "../api/client"; + +interface AuthImageProps extends ImgHTMLAttributes { + src: string; +} + +export function AuthImage({ src, ...props }: AuthImageProps) { + const [objectUrl, setObjectUrl] = useState(null); + + useEffect(() => { + let url: string | null = null; + client.get(src, { responseType: "blob" }).then((res) => { + url = URL.createObjectURL(res.data); + setObjectUrl(url); + }); + return () => { + if (url) URL.revokeObjectURL(url); + }; + }, [src]); + + if (!objectUrl) return null; + return ; +} diff --git a/frontend/src/pages/AnalysisView.tsx b/frontend/src/pages/AnalysisView.tsx index b5fba3e..1052383 100644 --- a/frontend/src/pages/AnalysisView.tsx +++ b/frontend/src/pages/AnalysisView.tsx @@ -3,6 +3,7 @@ import { useParams, useNavigate } from "react-router-dom"; import { useAnalysis, useDeleteAnalysis } from "../hooks/useAnalysis"; import { useAnalysisStore, type AnalysisTab } from "../stores/analysisStore"; import { getAnalysisImageUrl, checkAIInsightsAvailable, generateAIInsights } from "../api/analysis"; +import { AuthImage } from "../components/AuthImage"; import type { Insight } from "../types/analysis"; function getScoreInfo(score: number) { @@ -76,7 +77,7 @@ function ZoomableImage({ src, alt }: { src: string; alt: string }) { const zoom = useAnalysisStore((s) => s.zoom); return (
- {alt}{analysis.model}

- {`Heatmap:
- {analysis.name} { - (e.target as HTMLImageElement).style.display = "none"; - }} />