diff --git a/components/buying-guide/BuyingGuideProduct.tsx b/components/buying-guide/BuyingGuideProduct.tsx index af02851e..c5404de4 100644 --- a/components/buying-guide/BuyingGuideProduct.tsx +++ b/components/buying-guide/BuyingGuideProduct.tsx @@ -1,96 +1,188 @@ -"use client"; +// app/buying-guide/product/[id]/page.tsx +import Link from "next/link"; +import ReactMarkdown from "react-markdown"; -import { useEffect, useState } from "react"; -import { dxGet } from "./dx"; +const API_URL = process.env.NEXT_PUBLIC_API_BASE_URL; +const ASSET_URL = process.env.NEXT_PUBLIC_ASSET_URL; -type EntryDetail = { - submission_id: string | number; - title?: string | null; - brand?: string | null; - model?: string | null; - body?: string | null; - specs?: any; - gallery?: { directus_files_id: { id: string; filename_disk?: string } }[]; - thumb?: { id: string }; -}; +async function getEntry(id: string) { + const res = await fetch( + `${API_URL}/items/bg_entries/${id}?fields=*,links.id,links.text,links.url,links.target,scores.id,scores.cat,scores.value,scores.body,header.id,date_updated`, + { + cache: "no-store", + } + ); -function assetUrl(id?: string) { - if (!id) return ""; - return `/api/dx/assets/${id}`; + if (!res.ok) { + const error = await res.text(); + console.error(`Failed to fetch entry: ${error}`); + throw new Error(`Error fetching entry ${id}`); + } + + const { data } = await res.json(); + return data; } -export default function BuyingGuideProduct({ id }: { id: string | number }) { - const [rec, setRec] = useState(null); - const [loading, setLoading] = useState(true); +export default async function ProductDetail({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const id = (await params).id; + const entry = await getEntry(id); - useEffect(() => { - (async () => { - setLoading(true); - try { - const data = await dxGet("items/bg_entries", { - filter: JSON.stringify({ submission_id: { _eq: id } }), - fields: [ - "submission_id", - "title", - "brand", - "model", - "body", - "specs", - "thumb.id", - "gallery.directus_files_id.id", - ].join(","), - limit: 1, - }); - setRec(data?.[0] || null); - } finally { - setLoading(false); - } - })(); - }, [id]); + const avgScore = + entry?.scores?.length > 0 + ? ( + entry.scores.reduce((sum: number, s: any) => sum + Number(s.value), 0) / + entry.scores.length + ).toFixed(1) + : "N/A"; - if (loading) return
Loading…
; - if (!rec) return
Not found.
; - - const title = rec.model || rec.title || "Product"; - const images = [ - rec.thumb?.id, - ...(rec.gallery?.map(g => g.directus_files_id?.id).filter(Boolean) as string[]), - ].filter(Boolean); + const headerUrl = entry.header?.id + ? `${ASSET_URL}/assets/${entry.header.id}?cache-buster=${entry.date_updated}&key=system-large-contain` + : null; return ( -
-
-

- {rec.brand ? `${rec.brand} ` : ""}{title} -

- + {/* Header Banner */} + {headerUrl && ( +
+ Header Image +
+ )} + + {/* Title */} +
+
+

{entry.product_make}

+

{entry.product_model}

+
+
- {images.length > 0 && ( -
- {images.map((id) => ( - // eslint-disable-next-line @next/next/no-img-element - + {/* Links & Score Summary */} + {(Array.isArray(entry.links) || Array.isArray(entry.scores)) && ( +
+ {Array.isArray(entry.links) && entry.links.length > 0 && ( +
+

Links

+ +
+ )} + + {(Array.isArray(entry.scores) && entry.scores.length > 0) && ( +
+

Score Summary

+
    + {entry.scores.map((s: any, idx: number) => ( +
  • + {s.cat} + {s.value}/10 +
  • + ))} +
+

Total: {avgScore}

+
+ )} +
+ )} + + {/* Overview */} + {entry.review_overview_text && ( +
+

Overview

+ {entry.review_overview_text} +
+ )} + + {/* Intro */} + {entry.review_intro_text && ( +
+

{`${entry.product_make}, ${entry.product_model} Review by ${entry.author}`}

+ {entry.review_intro_text} +
+ )} + + {/* Detailed Scores */} + {(Array.isArray(entry.scores) && entry.scores.length > 0) && ( +
+ {entry.scores.map((s: any, idx: number) => ( +
+

+ {s.cat} – {s.value}/10 +

+
+ {s.body} +
+
))}
)} - {rec.body && ( -
+ {/* Recommendation */} + {entry.rec_text && ( +
+

Recommendation

+ {entry.rec_text} +
)} - {rec.specs && ( -
-            {JSON.stringify(rec.specs, null, 2)}
-            
+ {/* Updates */} + {entry.updates && ( +
+

Updates

+ {entry.updates} +
+ )} + + {/* Video */} + {entry.video_review_url && ( +
+

Video Review

+
+