Files

152 lines
4.2 KiB
TypeScript

// /lib/buildOverlaps.ts
import type { BuilderSlotKey } from "@/types/builderSlots";
type CategoryId = BuilderSlotKey;
export type OverlapChipModel = {
key: string;
tone: "warning" | "info";
label: string;
detail?: string;
};
export const COMPLETE_UPPER_CATEGORY: CategoryId = "complete-upper";
export const COMPLETE_LOWER_CATEGORY: CategoryId = "complete-lower";
export const UPPER_OVERLAP_CATEGORIES = new Set<CategoryId>([
"upper-receiver",
"bcg",
"barrel",
"gas-block",
"gas-tube",
"muzzle-device",
"suppressor",
"handguard",
"charging-handle",
]);
export const LOWER_OVERLAP_CATEGORIES = new Set<CategoryId>([
"lower-receiver",
"lower-parts-kit",
"trigger",
"grip",
"safety-selector",
"buffer",
"stock",
]);
export type BuildState = Partial<Record<CategoryId, string>>;
function selectedCount(build: BuildState, set: Set<CategoryId>) {
let count = 0;
for (const cid of set) if (build[cid]) count++;
return count;
}
function selectedList(build: BuildState, set: Set<CategoryId>) {
const list: CategoryId[] = [];
for (const cid of set) if (build[cid]) list.push(cid);
return list;
}
/**
* Chips to show on a given category row (education / “you may not need both”)
*/
export function getOverlapChipsForCategory(
categoryId: CategoryId,
build: BuildState
): OverlapChipModel[] {
const chips: OverlapChipModel[] = [];
const hasCompleteUpper = !!build[COMPLETE_UPPER_CATEGORY];
const hasCompleteLower = !!build[COMPLETE_LOWER_CATEGORY];
// ---- Upper overlap ----
if (categoryId === COMPLETE_UPPER_CATEGORY) {
const count = selectedCount(build, UPPER_OVERLAP_CATEGORIES);
if (count > 0) {
chips.push({
key: "upper-complete-overlaps-subparts",
tone: "warning",
label: "Overlaps selected upper parts",
detail: `${count} upper part${count === 1 ? "" : "s"} also selected`,
});
}
}
if (UPPER_OVERLAP_CATEGORIES.has(categoryId) && hasCompleteUpper) {
chips.push({
key: "upper-subpart-in-complete",
tone: "info",
label: "Included in Complete Upper",
detail: "You have both selected (compare if you want)",
});
}
// ---- Lower overlap ----
if (categoryId === COMPLETE_LOWER_CATEGORY) {
const count = selectedCount(build, LOWER_OVERLAP_CATEGORIES);
if (count > 0) {
chips.push({
key: "lower-complete-overlaps-subparts",
tone: "warning",
label: "Overlaps selected lower parts",
detail: `${count} lower part${count === 1 ? "" : "s"} also selected`,
});
}
}
if (LOWER_OVERLAP_CATEGORIES.has(categoryId) && hasCompleteLower) {
chips.push({
key: "lower-subpart-in-complete",
tone: "info",
label: "Included in Complete Lower",
detail: "You have both selected (compare if you want)",
});
}
return chips;
}
/**
* Non-blocking “heads up” messages when selecting a part.
* (Use for toasts / shareStatus strip — no auto-removal)
*/
export function getSelectionHints(
nextCategoryId: CategoryId,
build: BuildState
): string[] {
const hints: string[] = [];
if (nextCategoryId === COMPLETE_UPPER_CATEGORY) {
const overlaps = selectedList(build, UPPER_OVERLAP_CATEGORIES);
if (overlaps.length > 0) {
hints.push(
"Heads up: Complete Upper overlaps with some selected upper parts. Nothing was removed — compare options and keep what you want."
);
}
}
if (UPPER_OVERLAP_CATEGORIES.has(nextCategoryId) && build[COMPLETE_UPPER_CATEGORY]) {
hints.push(
"Heads up: You also have a Complete Upper selected. Nothing was removed — compare options and keep what you want."
);
}
if (nextCategoryId === COMPLETE_LOWER_CATEGORY) {
const overlaps = selectedList(build, LOWER_OVERLAP_CATEGORIES);
if (overlaps.length > 0) {
hints.push(
"Heads up: Complete Lower overlaps with some selected lower parts. Nothing was removed — compare options and keep what you want."
);
}
}
if (LOWER_OVERLAP_CATEGORIES.has(nextCategoryId) && build[COMPLETE_LOWER_CATEGORY]) {
hints.push(
"Heads up: You also have a Complete Lower selected. Nothing was removed — compare options and keep what you want."
);
}
return hints;
}