72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import type {
|
|
FlooringPlan,
|
|
PieceKey,
|
|
PlanFocus,
|
|
PlanMaterial,
|
|
Project,
|
|
SkirtingPlan,
|
|
} from './types';
|
|
import type { CutData } from './cut-list';
|
|
|
|
export const pieceKey = (material: PlanMaterial, id: string): PieceKey => `${material}:${id}`;
|
|
export const boardKey = (material: PlanMaterial, id: string) =>
|
|
`${material === 'flooring' ? 'floor' : 'skirting'}:${id}`;
|
|
|
|
export interface BoardMatches {
|
|
pieceKeys: Set<PieceKey>;
|
|
roomIds: string[];
|
|
boardKeys: Set<string>;
|
|
materials: Set<PlanMaterial>;
|
|
}
|
|
|
|
/** User text searches cut codes or room names. Location is explicit, never encoded as a query. */
|
|
export function findBoardMatches(
|
|
project: Project,
|
|
flooring: FlooringPlan,
|
|
skirting: SkirtingPlan,
|
|
query: string,
|
|
focus: PlanFocus | null = null,
|
|
): BoardMatches {
|
|
const text = query.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
const result: BoardMatches = {
|
|
pieceKeys: new Set(),
|
|
roomIds: [],
|
|
boardKeys: new Set(),
|
|
materials: new Set(),
|
|
};
|
|
if (!text && !focus) return result;
|
|
const codes = new Set(text.split(/\s*[+,]\s*/));
|
|
const matchingRooms = new Set(
|
|
project.rooms
|
|
.filter((room) => room.name.toLowerCase().replace(/\s+/g, ' ').includes(text))
|
|
.map((room) => room.id),
|
|
);
|
|
const roomIds = new Set<string>();
|
|
for (const [material, pieces] of [
|
|
['flooring', flooring.pieces],
|
|
['skirting', skirting.pieces],
|
|
] as const) {
|
|
for (const piece of pieces) {
|
|
const matches = focus
|
|
? material === focus.material &&
|
|
(focus.kind === 'board' ? piece.stockId : piece.id) === focus.id
|
|
: codes.has(piece.id.toLowerCase()) || matchingRooms.has(piece.roomId);
|
|
if (!matches) continue;
|
|
result.pieceKeys.add(pieceKey(material, piece.id));
|
|
roomIds.add(piece.roomId);
|
|
result.boardKeys.add(boardKey(material, piece.stockId));
|
|
result.materials.add(material);
|
|
}
|
|
}
|
|
result.roomIds = project.rooms.filter((room) => roomIds.has(room.id)).map((room) => room.id);
|
|
return result;
|
|
}
|
|
|
|
export function focusLabel(focus: PlanFocus, cuts: CutData): string {
|
|
if (focus.kind === 'piece') return focus.id;
|
|
const group = (focus.material === 'flooring' ? cuts.floorGroups : cuts.skirtGroups).get(focus.id);
|
|
return (
|
|
group?.map((piece) => piece.id).join(' + ') ||
|
|
(focus.material === 'flooring' ? 'Uncut floorboard' : 'Uncut skirting board')
|
|
);
|
|
}
|