fixed platform selector and part selector

This commit is contained in:
2025-12-11 16:27:28 -05:00
parent b26dcb947e
commit 777618f684
3 changed files with 498 additions and 438 deletions
File diff suppressed because it is too large Load Diff
+42 -4
View File
@@ -87,7 +87,16 @@ export default function GunbuilderPage() {
const [parts, setParts] = useState<Part[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [platform, setPlatform] = useState<(typeof PLATFORMS)[number]>("AR-15");
const isValidPlatform = (
value: string | null
): value is (typeof PLATFORMS)[number] =>
!!value && (PLATFORMS as readonly string[]).includes(value);
const [platform, setPlatform] = useState<(typeof PLATFORMS)[number]>(() => {
if (typeof window === "undefined") return "AR-15";
const initial = new URLSearchParams(window.location.search).get("platform");
return isValidPlatform(initial) ? initial : "AR-15";
});
const [build, setBuild] = useState<BuildState>(() => {
if (typeof window !== "undefined") {
const stored = localStorage.getItem(STORAGE_KEY);
@@ -189,11 +198,26 @@ export default function GunbuilderPage() {
return updated;
});
router.replace("/builder", { scroll: false });
const qp = searchParams.get("platform");
const nextPlatform = isValidPlatform(qp) ? qp : platform;
router.replace(
`/builder?platform=${encodeURIComponent(nextPlatform)}`,
{
scroll: false,
}
);
}
}
}, [searchParams, router]);
useEffect(() => {
const qp = searchParams.get("platform");
if (isValidPlatform(qp) && qp !== platform) {
setPlatform(qp);
}
}, [searchParams, platform]);
// Persist build state to localStorage whenever it changes
useEffect(() => {
if (typeof window !== "undefined") {
@@ -695,10 +719,24 @@ export default function GunbuilderPage() {
<Link
href={{
pathname: `/builder/${category.id}`,
query: { platform },
query: platform ? { platform } : {},
}}
className="inline-flex items-center gap-1.5 whitespace-nowrap rounded-md border border-zinc-700 bg-zinc-900/70 px-3 py-1.5 text-xs font-medium text-zinc-300 hover:bg-zinc-800 hover:border-zinc-600 transition-colors"
>
Choose a Part
<svg
className="w-3.5 h-3.5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 4v16m8-8H4"
/>
</svg>
<span>Choose a Part</span>
</Link>
) : (
<span className="text-[0.7rem] text-zinc-600">
+11 -3
View File
@@ -9,6 +9,7 @@ interface CategoryColumnProps {
parts: Part[];
selectedPartId?: string;
onSelectPart: (partId: string) => void;
platform?: string;
}
export function CategoryColumn({
@@ -16,6 +17,7 @@ export function CategoryColumn({
parts,
selectedPartId,
onSelectPart,
platform,
}: CategoryColumnProps) {
// Show selected part if available, otherwise show placeholder
const displayedPart = selectedPartId
@@ -37,8 +39,11 @@ export function CategoryColumn({
<div className="w-full border border-zinc-700 rounded-md p-3 mb-2 flex items-center justify-between gap-3">
<p className="text-sm text-zinc-500">No part selected</p>
<Link
href={`/builder/${category.id}`}
className="inline-flex items-center gap-2 rounded-md border border-zinc-700 bg-zinc-900/60 px-3 py-1.5 text-xs font-medium text-zinc-200 hover:bg-zinc-800 hover:border-zinc-500 transition-colors"
href={{
pathname: `/builder/${category.id}`,
query: platform ? { platform } : {},
}}
className="inline-flex w-full items-center justify-center rounded-md border border-zinc-700 bg-zinc-900 px-4 py-2 text-xs font-semibold text-zinc-100 hover:bg-zinc-800 hover:border-zinc-600 transition-colors"
>
<svg
className="w-4 h-4"
@@ -68,7 +73,10 @@ export function CategoryColumn({
</div>
{parts.length >= 1 && (
<Link
href={`/builder/${category.id}`}
href={{
pathname: `/builder/${category.id}`,
query: platform ? { platform } : {},
}}
className="mt-2 w-full rounded-md border border-zinc-700 bg-zinc-900/50 px-3 py-2 text-xs font-medium text-zinc-300 hover:bg-zinc-800 hover:border-zinc-600 transition-colors text-center"
>
View All ({parts.length})