101 lines
3.0 KiB
TypeScript
101 lines
3.0 KiB
TypeScript
import type { BuilderSlotKey } from "@/types/builderSlots";
|
|
|
|
/**
|
|
* Normalize backend part roles into a canonical kebab-case form.
|
|
* - trims whitespace
|
|
* - lowercases
|
|
* - converts snake_case / ENUM_CASE to kebab-case
|
|
*/
|
|
export const normalizePartRole = (role: string) =>
|
|
role.trim().toLowerCase().replace(/_/g, "-");
|
|
|
|
/**
|
|
* Maps canonical kebab-case CategoryIds to their associated part roles from the backend.
|
|
*
|
|
* Notes:
|
|
* - Keep the list here as the *source of truth*.
|
|
* - The derived `PART_ROLE_TO_CATEGORY` map below stores both the original and normalized keys.
|
|
*/
|
|
export const CATEGORY_TO_PART_ROLES: Partial<Record<BuilderSlotKey, string[]>> = {
|
|
// ===== UPPER =====
|
|
"upper-receiver": ["upper-receiver"],
|
|
// (optional) Back-compat if anything still uses the old ids:
|
|
// upper: ["upper-receiver", "upper"],
|
|
|
|
"complete-upper": ["complete-upper"],
|
|
barrel: ["barrel"],
|
|
"gas-block": ["gas-block"],
|
|
"gas-tube": ["gas-tube"],
|
|
"muzzle-device": ["muzzle-device", "compensator", "brake"],
|
|
suppressor: ["suppressor"],
|
|
handguard: ["handguard"],
|
|
"charging-handle": ["charging-handle"],
|
|
bcg: ["bcg", "bolt-carrier-group"],
|
|
|
|
// ===== LOWER =====
|
|
"lower-receiver": ["lower-receiver", "lower", "LOWER_RECEIVER_STRIPPED"],
|
|
// (optional) Back-compat if anything still uses the old ids:
|
|
|
|
"complete-lower": ["complete-lower"],
|
|
// Lower Parts Kit (LPK)
|
|
"lower-parts-kit": ["lower-parts-kit", "lower-parts"],
|
|
trigger: ["trigger", "trigger-kit"],
|
|
grip: ["pistol-grip", "grip"],
|
|
safety: ["safety", "safety-selector"],
|
|
buffer: ["buffer-kit", "buffer"],
|
|
stock: ["stock"],
|
|
|
|
// ===== OPTICS =====
|
|
sights: ["sight", "sights", "iron-sights"],
|
|
optic: ["optic", "optics"],
|
|
|
|
// ===== ACCESSORIES =====
|
|
magazine: ["magazine", "mag", "magazine-ar15", "magazine-308", "drum-magazine"],
|
|
"weapon-light": [
|
|
"weapon-light",
|
|
"light",
|
|
"weapon-light-laser",
|
|
"light-laser-combo",
|
|
"laser",
|
|
],
|
|
foregrip: ["vertical-grip", "angled-foregrip", "foregrip", "handstop"],
|
|
bipod: ["bipod"],
|
|
sling: ["sling", "sling-mount", "sling-swivel", "qd-sling-mount"],
|
|
"rail-accessory": [
|
|
"rail-section",
|
|
"picatinny-rail-section",
|
|
"m-lok-rail-section",
|
|
"keymod-rail-section",
|
|
"rail-cover",
|
|
"rail-panel",
|
|
],
|
|
tools: [
|
|
"tool",
|
|
"armorer-tool",
|
|
"armorer-wrench",
|
|
"cleaning-kit",
|
|
"bore-snake",
|
|
"vise-block",
|
|
"torque-wrench",
|
|
],
|
|
};
|
|
|
|
/**
|
|
* Reverse lookup: backend partRole -> CategoryId.
|
|
*
|
|
* Implementation details:
|
|
* - Stores BOTH the original role and its normalized version as keys.
|
|
* - De-dupes role lists per category.
|
|
*/
|
|
export const PART_ROLE_TO_CATEGORY: Record<string, BuilderSlotKey> = Object.entries(
|
|
CATEGORY_TO_PART_ROLES
|
|
).reduce((acc, [categoryId, roles]) => {
|
|
const unique = Array.from(new Set(roles ?? []));
|
|
|
|
for (const role of unique) {
|
|
acc[role] = categoryId as BuilderSlotKey;
|
|
acc[normalizePartRole(role)] = categoryId as BuilderSlotKey;
|
|
}
|
|
|
|
return acc;
|
|
}, {} as Record<string, BuilderSlotKey>); |