#!/bin/zsh echo "🎨 Setting up UI integration (Next.js App Router)..." BASE="src/app" COMP="src/app/components" UTIL="src/lib/ui" mkdir -p "$COMP" mkdir -p "$UTIL" ############################################# # API CLIENT (simple fetch helpers) ############################################# cat > "$UTIL/api.js" << 'EOF' export async function fetchJSON(url) { const res = await fetch(url, { cache: "no-store" }); if (!res.ok) return null; return res.json(); } export function getModel(id) { return fetchJSON(`/api/models/${id}`); } export function getPart(id) { return fetchJSON(`/api/parts/${id}`); } export function getCompatibleParts(modelId) { return fetchJSON(`/api/compatibility/model/${modelId}`); } export function getCompatibleModels(partId) { return fetchJSON(`/api/compatibility/part/${partId}`); } EOF ############################################# # COMPONENTS ############################################# # ModelCard.js cat > "$COMP/ModelCard.js" << 'EOF' export default function ModelCard({ model }) { return (

{model.name}

{model.brand} • {model.scale}

); } EOF # PartCard.js cat > "$COMP/PartCard.js" << 'EOF' export default function PartCard({ part }) { return (

{part.name}

ID: {part.id}

); } EOF # SearchBar.js cat > "$COMP/SearchBar.js" << 'EOF' "use client"; import { useState } from "react"; export default function SearchBar({ onSearch }) { const [text, setText] = useState(""); return (
setText(e.target.value)} />
); } EOF ############################################# # UI: Model Page Integration ############################################# cat > "$BASE/model/[modelId]/page.js" << 'EOF' import { getModel, getCompatibleParts } from "@/src/lib/ui/api"; import PartCard from "@/src/app/components/PartCard"; export default async function ModelPage({ params }) { const model = await getModel(params.modelId); const parts = await getCompatibleParts(params.modelId); if (!model) return

Model not found

; return (

{model.name}

{model.brand} • {model.scale}

Compatible Parts

{Array.isArray(parts) && parts.length > 0 ? ( parts.map(item => ) ) : (

No compatible parts.

)}
); } EOF ############################################# # UI: Part Page Integration ############################################# cat > "$BASE/part/[partId]/page.js" << 'EOF' import { getPart, getCompatibleModels } from "@/src/lib/ui/api"; import ModelCard from "@/src/app/components/ModelCard"; export default async function PartDetailPage({ params }) { const part = await getPart(params.partId); const models = await getCompatibleModels(params.partId); if (!part) return

Part not found

; return (

{part.name}

ID: {part.id}

Compatible Models

{Array.isArray(models) && models.length > 0 ? ( models.map(item => ( )) ) : (

No compatible models.

)}
); } EOF ############################################# # UI: Category Page Integration ############################################# cat > "$BASE/category/[modelId]/[categoryName]/page.js" << 'EOF' import { getModel, getCompatibleParts } from "@/src/lib/ui/api"; import PartCard from "@/src/app/components/PartCard"; export default async function CategoryPage({ params }) { const model = await getModel(params.modelId); const allParts = await getCompatibleParts(params.modelId); if (!model) return

Model not found

; const parts = allParts ? allParts.filter(p => p.part.category === params.categoryName) : []; return (

{params.categoryName} for {model.name}

{parts.length ? ( parts.map(p => ( )) ) : (

No compatible parts in this category.

)}
); } EOF ############################################# # UI: Compatibility Explorer Page ############################################# cat > "$BASE/compatibility/page.js" << 'EOF' "use client"; import { useState } from "react"; import { fetchJSON } from "@/src/lib/ui/api"; import ModelCard from "../components/ModelCard"; import PartCard from "../components/PartCard"; export default function CompatibilityPage() { const [query, setQuery] = useState(""); const [result, setResult] = useState([]); async function compare() { const modelData = await fetchJSON(`/api/compatibility/model/${query}`); const partData = await fetchJSON(`/api/compatibility/part/${query}`); setResult(modelData || partData || []); } return (

Compatibility Explorer

setQuery(e.target.value)} />
{result.map(item => item.model ? ( ) : ( ) )}
); } EOF ############################################# # UI: Home Page Search Integration ############################################# cat > "$BASE/page.js" << 'EOF' "use client"; import { useState } from "react"; import SearchBar from "./components/SearchBar"; import { searchModels, searchParts } from "@/src/lib/search/search"; export default function HomePage() { const [results, setResults] = useState([]); async function handleSearch(query) { const models = searchModels(query); const parts = searchParts(query); setResults([...models, ...parts]); } return (

RC Compatibility Explorer

{results.map(item => item.categories ? (
{item.name} — Model
) : (
{item.name} — Part
) )}
); } EOF echo "🎉 UI integration created successfully!"