// types/builderSlots.ts export type CategoryGroup = "lower" | "upper" | "accessories"; /** * Canonical key used across UI, localStorage, and (ideally) backend part_roles.key. * Keep these in sync with part_roles.key to avoid mapping hell. */ export type BuilderSlotKey = // ===== LOWER ===== | "lower-receiver" | "complete-lower" | "lower-parts-kit" | "trigger" | "grip" | "safety-selector" | "buffer" | "stock" // ===== UPPER ===== | "upper-receiver" | "complete-upper" | "barrel" | "handguard" | "gas-block" | "gas-tube" | "muzzle-device" | "bcg" | "charging-handle" | "suppressor" | "sights" | "optic" // ===== ACCESSORIES ===== | "magazine" | "weapon-light" | "foregrip" | "bipod" | "sling" | "rail-accessory" | "tools"; export interface Category { id: BuilderSlotKey; name: string; description?: string; group?: CategoryGroup; } export interface Part { id: string; name: string; brand: string; categoryId: BuilderSlotKey; price: number; affiliateUrl?: string; url?: string; imageUrl?: string; notes?: string; } /** * Legacy localStorage / URL keys support (read-only). * Add/remove as needed during migration. */ const LEGACY_SLOT_ALIASES: Record = { completeUpper: "complete-upper", gasBlock: "gas-block", gasTube: "gas-tube", muzzleDevice: "muzzle-device", chargingHandle: "charging-handle", completeLower: "complete-lower", lowerParts: "lower-parts-kit", weaponLight: "weapon-light", railAccessory: "rail-accessory", // also handle older kebab mismatches if they exist: "lower-parts": "lower-parts-kit", safety: "safety-selector", }; export function normalizeSlotKey(key: string): BuilderSlotKey | null { const k = (key ?? "").trim(); if (!k) return null; return (LEGACY_SLOT_ALIASES[k] ?? (k as BuilderSlotKey)) || null; }