From fece168486f9058316308899393d049e12e4a91f Mon Sep 17 00:00:00 2001 From: DavidHerran Date: Tue, 5 May 2026 09:25:45 -0500 Subject: [PATCH] fix: FluxAI image paths now include the node slug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two AI tool cards rendered inside the chat — CaseStudyViewer (the "Show me proven installations" card) and EquipmentConfigurator (the "Show equipment specs" card) — were composing image URLs without the node-slug segment: /cases/ ← what the cards were emitting (404) /cases// ← what the public site actually serves Result: cover images and gallery thumbnails inside chat cards came back as broken-image icons, while the same files rendered fine on /en/applications/ and inside the CaseStudyModal (those already used the correct path). Fix: both components now derive the slug from data.title with the same nodeToSlug() the public pages use, and prefix it on every /cases/ URL — cover and gallery thumbnails alike. CHANGES (2 files) - src/components/ai/CaseStudyViewer.tsx - Added local nodeToSlug() helper (mirrors ApplicationClient + assetFolders) - coverSrc: /cases/${nodeSlug}/${mediaFileName} - gallery image: /cases/${nodeSlug}/${img} - src/components/ai/EquipmentConfigurator.tsx - Added local nodeToSlug() helper - coverSrc: /cases/${nodeSlug}/${mediaFileName} No backend / API / DB changes. Pure client-side path correction. --- src/components/ai/CaseStudyViewer.tsx | 12 ++++++++++-- src/components/ai/EquipmentConfigurator.tsx | 9 ++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/ai/CaseStudyViewer.tsx b/src/components/ai/CaseStudyViewer.tsx index 32bd520..e9d4e90 100644 --- a/src/components/ai/CaseStudyViewer.tsx +++ b/src/components/ai/CaseStudyViewer.tsx @@ -5,6 +5,13 @@ import { MapPin, Factory, Zap, Clock, ChevronDown, ArrowRight, Globe2, Image as import { useState } from "react"; import Image from "next/image"; +// Slugify the node title the same way ApplicationClient + assetFolders do — +// keeps image paths consistent with the on-disk layout +// (/cases//). +function nodeToSlug(title: string): string { + return title.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); +} + // ── Interface matches GlobalNode shape from Prisma ── interface CaseStudyData { found: boolean; @@ -50,7 +57,8 @@ export default function CaseStudyViewer({ data }: { data: CaseStudyData }) { if (!data.found) return null; const accent = ACCENTS[data.industry] || ACCENTS.textile; - const coverSrc = data.mediaFileName ? `/cases/${data.mediaFileName}` : null; + const nodeSlug = nodeToSlug(data.title); + const coverSrc = data.mediaFileName ? `/cases/${nodeSlug}/${data.mediaFileName}` : null; const appLabel = data.application.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase()); return ( @@ -192,7 +200,7 @@ export default function CaseStudyViewer({ data }: { data: CaseStudyData }) {
{data.gallery.slice(0, 6).map((img, i) => (
- {`Gallery + {`Gallery
))}
diff --git a/src/components/ai/EquipmentConfigurator.tsx b/src/components/ai/EquipmentConfigurator.tsx index 8d690ad..a51d6f4 100644 --- a/src/components/ai/EquipmentConfigurator.tsx +++ b/src/components/ai/EquipmentConfigurator.tsx @@ -5,6 +5,12 @@ import { Cpu, ArrowRight, Settings2, ChevronDown, MapPin, Factory, Zap, Box } fr import { useState } from "react"; import Image from "next/image"; +// Same slugger as the public-facing pages so cover images resolve to the +// /cases// layout that's actually on disk. +function nodeToSlug(title: string): string { + return title.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, ""); +} + // ── Interface matches GlobalNode + specificDatasheetJson from Prisma ── interface EquipmentData { found: boolean; @@ -39,7 +45,8 @@ export default function EquipmentConfigurator({ data }: { data: EquipmentData }) if (!data.found) return null; - const coverSrc = data.mediaFileName ? `/cases/${data.mediaFileName}` : null; + const nodeSlug = nodeToSlug(data.title); + const coverSrc = data.mediaFileName ? `/cases/${nodeSlug}/${data.mediaFileName}` : null; const appLabel = data.application.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase()); // Find key specs for header pills (power, frequency, model — from datasheet)