fixed part role mapping to categories. set a const for categories
This commit is contained in:
+87
-34
@@ -6,6 +6,7 @@ import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { CATEGORIES } from "@/data/gunbuilderParts";
|
||||
import type { CategoryId, Part } from "@/types/gunbuilder";
|
||||
import { CategoryColumn } from "@/components/CategoryColumn";
|
||||
import { PART_ROLE_TO_CATEGORY } from "@/data/partRoleMappings";
|
||||
|
||||
type GunbuilderProductFromApi = {
|
||||
id: number; // backend numeric id
|
||||
@@ -21,19 +22,6 @@ type GunbuilderProductFromApi = {
|
||||
const API_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||
|
||||
// Map backend partRole to your existing CategoryId values.
|
||||
const PART_ROLE_TO_CATEGORY: Record<string, CategoryId> = {
|
||||
"upper-receiver": "upper" as CategoryId,
|
||||
barrel: "barrel" as CategoryId,
|
||||
handguard: "handguard" as CategoryId,
|
||||
"charging-handle": "chargingHandle" as CategoryId,
|
||||
"buffer-kit": "buffer" as CategoryId,
|
||||
"lower-parts-kit": "lowerParts" as CategoryId,
|
||||
sight: "sights" as CategoryId,
|
||||
"lower-receiver": "lower" as CategoryId,
|
||||
optic: "optic" as CategoryId,
|
||||
stock: "stock" as CategoryId,
|
||||
};
|
||||
|
||||
type BuildState = Partial<Record<CategoryId, string>>; // categoryId -> partId
|
||||
|
||||
@@ -54,22 +42,37 @@ const CATEGORY_GROUPS: {
|
||||
id: "lower-group",
|
||||
label: "Lower Receiver Parts",
|
||||
description:
|
||||
"Everything from the serialized lower to small parts and core controls.",
|
||||
categoryIds: ["lower", "lowerParts", "stock", "buffer"] as CategoryId[],
|
||||
"Everything from the serialized lower to small parts, fire control, and core controls.",
|
||||
categoryIds: [
|
||||
"lower",
|
||||
"completeLower",
|
||||
"lowerParts",
|
||||
"trigger",
|
||||
"grip",
|
||||
"safety",
|
||||
"buffer",
|
||||
"stock",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "upper-group",
|
||||
label: "Upper Receiver Parts",
|
||||
description:
|
||||
"Barrel, upper, handguard, and the parts that keep the rifle cycling.",
|
||||
"Barrel, upper, gas system, and the parts that keep the rifle cycling.",
|
||||
categoryIds: [
|
||||
"upper",
|
||||
"completeUpper",
|
||||
"bcg",
|
||||
"barrel",
|
||||
"gasBlock",
|
||||
"gasTube",
|
||||
"muzzleDevice",
|
||||
"suppressor",
|
||||
"handguard",
|
||||
"chargingHandle",
|
||||
"sights",
|
||||
"optic",
|
||||
] as CategoryId[],
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -92,6 +95,7 @@ export default function GunbuilderPage() {
|
||||
}
|
||||
return {};
|
||||
});
|
||||
const [layoutMode, setLayoutMode] = useState<"cards" | "list">("cards");
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
@@ -266,6 +270,35 @@ export default function GunbuilderPage() {
|
||||
<div className="grid gap-4 lg:grid-cols-[3fr,1.25fr]">
|
||||
{/* Categories/parts */}
|
||||
<section className="rounded-lg border border-zinc-800 bg-zinc-950/60 p-3 md:p-4">
|
||||
<div className="mb-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p className="text-xs text-zinc-500">
|
||||
Choose one part per category. Switch layouts to browse by cards or a tighter list view.
|
||||
</p>
|
||||
<div className="inline-flex items-center rounded-md border border-zinc-700 bg-zinc-900/70 text-[0.7rem]">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setLayoutMode("cards")}
|
||||
className={`px-2.5 py-1 rounded-l-md border-r border-zinc-700 transition-colors ${
|
||||
layoutMode === "cards"
|
||||
? "bg-amber-500/20 text-amber-200"
|
||||
: "text-zinc-400 hover:bg-zinc-800"
|
||||
}`}
|
||||
>
|
||||
Card view
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setLayoutMode("list")}
|
||||
className={`px-2.5 py-1 rounded-r-md transition-colors ${
|
||||
layoutMode === "list"
|
||||
? "bg-amber-500/20 text-amber-200"
|
||||
: "text-zinc-400 hover:bg-zinc-800"
|
||||
}`}
|
||||
>
|
||||
List view
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{loading && (
|
||||
<p className="text-sm text-zinc-500">
|
||||
Loading parts from backend…
|
||||
@@ -303,23 +336,43 @@ export default function GunbuilderPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{groupCategories.map((category) => (
|
||||
<div
|
||||
key={category.id}
|
||||
className="border border-zinc-800 rounded-md p-2 md:p-3 bg-zinc-950/60"
|
||||
>
|
||||
<CategoryColumn
|
||||
category={category}
|
||||
parts={partsByCategory[category.id]}
|
||||
selectedPartId={build[category.id]}
|
||||
onSelectPart={(partId) =>
|
||||
handleSelectPart(category.id, partId)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{layoutMode === "cards" ? (
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{groupCategories.map((category) => (
|
||||
<div
|
||||
key={category.id}
|
||||
className="border border-zinc-800 rounded-md p-2 md:p-3 bg-zinc-950/60"
|
||||
>
|
||||
<CategoryColumn
|
||||
category={category}
|
||||
parts={partsByCategory[category.id]}
|
||||
selectedPartId={build[category.id]}
|
||||
onSelectPart={(partId) =>
|
||||
handleSelectPart(category.id, partId)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{groupCategories.map((category) => (
|
||||
<div
|
||||
key={category.id}
|
||||
className="border border-zinc-800 rounded-md p-2 md:p-3 bg-zinc-950/60 flex flex-col md:flex-row md:items-start md:justify-between gap-3"
|
||||
>
|
||||
<CategoryColumn
|
||||
category={category}
|
||||
parts={partsByCategory[category.id]}
|
||||
selectedPartId={build[category.id]}
|
||||
onSelectPart={(partId) =>
|
||||
handleSelectPart(category.id, partId)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user