From 8d7809ccf1aee4e024d3861ee82ee2e04363d182 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 26 Dec 2025 21:04:33 -0500 Subject: [PATCH] added stuff to builds/details --- app/builds/[buildId]/page.tsx | 409 +++++++++++++++++++++++++++++++--- 1 file changed, 375 insertions(+), 34 deletions(-) diff --git a/app/builds/[buildId]/page.tsx b/app/builds/[buildId]/page.tsx index b98e234..cfb9792 100644 --- a/app/builds/[buildId]/page.tsx +++ b/app/builds/[buildId]/page.tsx @@ -1,16 +1,37 @@ +// app/builds/[buildId]/page.tsx import Link from "next/link"; import { notFound } from "next/navigation"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080"; +function formatMoney(n?: number | null) { + if (n == null) return "—"; + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + maximumFractionDigits: 0, + }).format(n); +} + +function timeAgo(iso?: string | null) { + if (!iso) return ""; + const d = new Date(iso); + const diff = Math.max(0, Date.now() - d.getTime()); + const mins = Math.floor(diff / 60000); + if (mins < 60) return `${mins}m ago`; + const hrs = Math.floor(mins / 60); + if (hrs < 24) return `${hrs}h ago`; + const days = Math.floor(hrs / 24); + return `${days}d ago`; +} + export default async function BuildBreakdownPage({ params, }: { params: { buildId: string }; }) { - // You may need to add/confirm this endpoint in backend: - // GET /api/v1/builds/{uuid} + // Public detail endpoint const res = await fetch(`${API_BASE_URL}/api/v1/builds/${params.buildId}`, { cache: "no-store", }); @@ -20,47 +41,367 @@ export default async function BuildBreakdownPage({ const build = await res.json().catch(() => null); if (!build) return notFound(); + const items: any[] = build.items ?? []; + + const total = items.reduce((sum, it) => { + const qty = Number(it.quantity ?? 1); + const price = it.bestPrice == null ? 0 : Number(it.bestPrice); + return sum + qty * price; + }, 0); + + const images: any[] = build.images ?? build.photos ?? build.media ?? []; + return ( -
- - ← Back to Community Builds - +
+ {/* Header crumb */} +
+ + ← Back to Community Builds + -
-

- {build.title ?? "Untitled build"} -

+
+ + Public Build + + {build.updatedAt && ( + + updated {timeAgo(build.updatedAt)} + + )} +
+
- {build.description && ( -

{build.description}

- )} + {/* Layout */} +
+ {/* Post column */} +
+ {/* “Reddit-ish” Post Card */} +
+
+ {/* Vote rail */} +
+ +
+ +
-
-

Parts

- - {/* Adjust keys to match your API payload */} -
- {(build.items ?? build.buildItems ?? []).map((it: any) => ( -
-
-
- {it.product?.name ?? it.name ?? "Part"} -
-
- {it.slot ?? it.partRole ?? "—"} -
+ {/* Post body */} +
+ {/* Meta */} +
+ + r/BattlBuilders + + + posted by + u/anonymous + {build.createdAt && ( + <> + + {timeAgo(build.createdAt)} + + )}
-
- x{it.quantity ?? 1} + + {/* Title */} +

+ {build.title ?? "Untitled Build"} +

+ + {/* Description */} + {build.description ? ( +

+ {build.description} +

+ ) : ( +

+ {/* placeholder copy */} + Field notes coming soon. This build breakdown will include + purpose, tradeoffs, and why each part made the cut. +

+ )} + + {/* Action bar */} +
+ + + + +
+ Est. Total + + {formatMoney(total)} + +
- ))} +
+
+ + {/* Parts card */} +
+
+

Parts

+
{items.length} items
+
+ +
+ {items.map((it) => ( +
+ {/* Thumb */} +
+ {it.productImageUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + {it.productName + ) : ( +
+ IMG +
+ )} +
+ + {/* Info */} +
+
+ {it.productName ?? "Part"} +
+
+ + {it.slot ?? "slot"} + + {it.productBrand && {it.productBrand}} + + x{it.quantity ?? 1} +
+
+ + {/* Price */} +
+
+ {formatMoney(it.bestPrice)} +
+ +
+
+ ))} +
+
+ + {/* Gallery */} +
+
+

+ Gallery +

+ user submitted +
+ {images.length === 0 ? ( +
+

+ No photos yet. Be the first to add a build pic. +

+

+ (Upload UI coming soon — we’ll store and moderate images + per build.) +

+ + {/* Mock thumbnails */} +
+ {Array.from({ length: 8 }).map((_, i) => ( +
+ IMG +
+ ))} +
+ + +
+ ) : ( +
+ {/* “Hero” preview */} +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + Build photo +
+ + {/* Thumbs */} +
+ {images.slice(0, 12).map((img, idx) => ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {`Build +
+ ))} +
+ +
+ + + + {images.length} photos + +
+
+ )} +
+ + {/* Comments (placeholder) */} +
+
+

Comments

+ mocked +
+ +
+ {[ + { + user: "u/gearhead", + body: "Solid parts list. Any reason you went with that upper over a BCM?", + }, + { + user: "u/OP", + body: "Mostly availability + price. I’ll probably swap once I track deals for a week.", + }, + { + user: "u/boltcarrier", + body: "Would love to see this with a pinned/weld option for 14.5 builds.", + }, + ].map((c, idx) => ( +
+
+ {c.user === "u/OP" ? "OP" : "u"} +
+
+
+ {c.user} • 1h ago +
+
+ {c.body} +
+
+ + + +
+
+
+ ))} + +
+ Commenting is coming soon. This will become the “breakdown” + thread for the build (notes, tradeoffs, deal alerts, revisions). +
+ +
+ + {/* Sidebar */} +
); -} \ No newline at end of file +}