added in admin pages to add models and parts

This commit is contained in:
2025-11-24 18:06:26 +00:00
parent f8bb195159
commit 2682308015
30 changed files with 1569 additions and 57 deletions
+259
View File
@@ -0,0 +1,259 @@
#!/bin/zsh
echo "🛠 Setting up Compatibility Explorer (Option A)..."
COMPAT_DIR="src/app/compatibility"
mkdir -p "$COMPAT_DIR"
cat > "$COMPAT_DIR/page.js" << 'EOF'
"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { CATEGORIES } from "@/lib/data/categories";
function ModeCard({ title, emoji, description, children }) {
return (
<div className="border rounded-xl p-6 shadow-sm bg-white flex flex-col gap-4">
<div className="flex items-center gap-3">
<div className="text-2xl">{emoji}</div>
<div>
<h2 className="font-semibold text-lg">{title}</h2>
<p className="text-sm text-gray-500">{description}</p>
</div>
</div>
<div className="mt-2 flex flex-col gap-3">{children}</div>
</div>
);
}
export default function CompatibilityPage() {
const [models, setModels] = useState([]);
const [parts, setParts] = useState([]);
const [loading, setLoading] = useState(true);
const [modelForParts, setModelForParts] = useState("");
const [partForModels, setPartForModels] = useState("");
const [modelA, setModelA] = useState("");
const [modelB, setModelB] = useState("");
const [categoryModel, setCategoryModel] = useState("");
const [category, setCategory] = useState("");
const router = useRouter();
useEffect(() => {
async function load() {
try {
const [modelsRes, partsRes] = await Promise.all([
fetch("/api/models"),
fetch("/api/parts"),
]);
const modelsJson = modelsRes.ok ? await modelsRes.json() : [];
const partsJson = partsRes.ok ? await partsRes.json() : [];
setModels(modelsJson || []);
setParts(partsJson || []);
} catch (e) {
console.error("Failed to load models/parts", e);
} finally {
setLoading(false);
}
}
load();
}, []);
function handleGoToModelCompatibility() {
if (!modelForParts) return;
router.push(`/model/${modelForParts}`);
}
function handleGoToPartCompatibility() {
if (!partForModels) return;
router.push(`/part/${partForModels}`);
}
function handleExploreCategory() {
if (!categoryModel || !category) return;
router.push(`/category/${categoryModel}/${category}`);
}
function handleCompareModels() {
if (!modelA || !modelB) return;
// Stubbed for now to avoid broken routes
alert("Model comparison view coming soon! (Hotshot vs Supershot, etc.)");
}
return (
<div className="space-y-10">
{/* Breadcrumb-ish header */}
<nav className="text-sm text-gray-500">
<Link href="/" className="hover:underline text-blue-600">
Home
</Link>{" "}
<span></span>{" "}
<span className="font-semibold text-gray-700">Compatibility Explorer</span>
</nav>
{/* Page Title */}
<div>
<h1 className="text-4xl font-bold mb-2">Compatibility Explorer</h1>
<p className="text-gray-600 max-w-2xl">
Discover cross-compatibility between RC models and parts. Use one of the
tools below to explore fitment, upgrades, and shared components.
</p>
</div>
{loading && (
<p className="text-gray-500">Loading models and parts…</p>
)}
{/* Mode Selector Grid */}
{!loading && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Mode 1: Model → Compatible Parts */}
<ModeCard
title="Model → Compatible Parts"
emoji="🔧"
description="Find every part that fits a specific RC model."
>
<select
className="border rounded-lg px-3 py-2"
value={modelForParts}
onChange={(e) => setModelForParts(e.target.value)}
>
<option value="">Select a model…</option>
{models.map((m) => (
<option key={m.id} value={m.id}>
{m.name} ({m.brand})
</option>
))}
</select>
<button
onClick={handleGoToModelCompatibility}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition disabled:opacity-50"
disabled={!modelForParts}
>
Show Compatible Parts
</button>
</ModeCard>
{/* Mode 2: Part → Compatible Models */}
<ModeCard
title="Part → Compatible Models"
emoji="🧩"
description="See all RC models that this part works with."
>
<select
className="border rounded-lg px-3 py-2"
value={partForModels}
onChange={(e) => setPartForModels(e.target.value)}
>
<option value="">Select a part…</option>
{parts.map((p) => (
<option key={p.id} value={p.id}>
{p.name} ({p.id})
</option>
))}
</select>
<button
onClick={handleGoToPartCompatibility}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition disabled:opacity-50"
disabled={!partForModels}
>
Show Compatible Models
</button>
</ModeCard>
{/* Mode 3: Compare Two Models (stubbed) */}
<ModeCard
title="Compare Two Models"
emoji="🔍"
description="See shared and unique parts between two models. (Coming soon)"
>
<div className="flex flex-col gap-2">
<select
className="border rounded-lg px-3 py-2"
value={modelA}
onChange={(e) => setModelA(e.target.value)}
>
<option value="">Select Model A…</option>
{models.map((m) => (
<option key={m.id} value={m.id}>
{m.name} ({m.brand})
</option>
))}
</select>
<select
className="border rounded-lg px-3 py-2"
value={modelB}
onChange={(e) => setModelB(e.target.value)}
>
<option value="">Select Model B…</option>
{models.map((m) => (
<option key={m.id} value={m.id}>
{m.name} ({m.brand})
</option>
))}
</select>
</div>
<button
onClick={handleCompareModels}
className="px-4 py-2 bg-gray-300 text-gray-700 rounded-lg cursor-not-allowed"
disabled
>
Compare (Coming Soon)
</button>
</ModeCard>
{/* Mode 4: Explore Categories */}
<ModeCard
title="Explore by Category"
emoji="📂"
description="Browse shocks, drivetrain, chassis, and more for a model."
>
<div className="flex flex-col gap-2">
<select
className="border rounded-lg px-3 py-2"
value={categoryModel}
onChange={(e) => setCategoryModel(e.target.value)}
>
<option value="">Select a model…</option>
{models.map((m) => (
<option key={m.id} value={m.id}>
{m.name} ({m.brand})
</option>
))}
</select>
<select
className="border rounded-lg px-3 py-2"
value={category}
onChange={(e) => setCategory(e.target.value)}
>
<option value="">Select a category…</option>
{CATEGORIES.map((cat) => (
<option key={cat} value={cat}>
{cat}
</option>
))}
</select>
</div>
<button
onClick={handleExploreCategory}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition disabled:opacity-50"
disabled={!categoryModel || !category}
>
Explore Category
</button>
</ModeCard>
</div>
)}
</div>
);
}
EOF
echo "🎉 Compatibility Explorer (Option A) page created at src/app/compatibility/page.js"