96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { dxGet } from "./dx";
|
|
|
|
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 };
|
|
};
|
|
|
|
function assetUrl(id?: string) {
|
|
if (!id) return "";
|
|
return `/api/dx/assets/${id}`;
|
|
}
|
|
|
|
export default function BuyingGuideProduct({ id }: { id: string | number }) {
|
|
const [rec, setRec] = useState<EntryDetail | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
setLoading(true);
|
|
try {
|
|
const data = await dxGet<EntryDetail[]>("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]);
|
|
|
|
if (loading) return <div className="text-sm text-zinc-400">Loading…</div>;
|
|
if (!rec) return <div className="text-sm text-zinc-400">Not found.</div>;
|
|
|
|
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);
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="flex flex-wrap items-end justify-between gap-2">
|
|
<h2 className="text-xl font-semibold">
|
|
{rec.brand ? `${rec.brand} ` : ""}{title}
|
|
</h2>
|
|
<a
|
|
href={`/buying-guide/${rec.submission_id}`}
|
|
className="text-sm underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
Open full page
|
|
</a>
|
|
</div>
|
|
|
|
{images.length > 0 && (
|
|
<div className="grid gap-2 grid-cols-2 sm:grid-cols-3 md:grid-cols-4">
|
|
{images.map((id) => (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img key={id} src={assetUrl(id)} alt="" className="rounded-md border object-cover w-full aspect-[4/3]" />
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{rec.body && (
|
|
<div className="prose prose-invert max-w-none" dangerouslySetInnerHTML={{ __html: rec.body }} />
|
|
)}
|
|
|
|
{rec.specs && (
|
|
<pre className="rounded-md border bg-muted/40 p-3 overflow-auto text-xs">
|
|
{JSON.stringify(rec.specs, null, 2)}
|
|
</pre>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|