import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; interface FloorStore { floors: Floor[]; setFloors: (floors: Floor[]) => void; addFloor: (floor: Floor) => void; updateFloor: (uuid: string, updated: Partial) => Floor | undefined; setFloorName: (uuid: string, name: string) => void; removeFloor: (uuid: string) => void; removePoint: (pointUuid: string) => { removedFloors: Floor[], updatedFloors: Floor[] }; removeFloorByPoints: (Points: [Point, Point]) => { removedFloors: Floor[], updatedFloors: Floor[] }; clearFloors: () => void; setPosition: ( pointUuid: string, position: [number, number, number] ) => Floor[] | []; setIsBeveled: (uuid: string, isBeveled: boolean) => void; setBevelStrength: (uuid: string, strength: number) => void; setDepth: (uuid: string, depth: number) => void; setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void; addDecal: (floors: string, decal: Decal) => void; updateDecal: (decalUuid: string, decal: Decal) => void; removeDecal: (decalUuid: string) => void; updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; updateDecalRotation: (decalUuid: string, rotation: number) => void; updateDecalScale: (decalUuid: string, scale: number) => void; getFloorById: (uuid: string) => Floor | undefined; getFloorsByPointId: (uuid: string) => Floor[] | []; getFloorByPoints: (points: Point[]) => Floor | undefined; getFloorPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; } export const createFloorStore = () => { return create()( immer((set, get) => ({ floors: [], setFloors: (floors) => set(state => { state.floors = floors; }), addFloor: (floor) => set(state => { state.floors.push(floor); }), updateFloor: (uuid, updated) => { let updatedFloor: Floor | undefined; set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { Object.assign(floor, updated); updatedFloor = JSON.parse(JSON.stringify(floor)); } }); return updatedFloor; }, setFloorName: (uuid, name) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { floor.floorName = name; } }), removeFloor: (uuid) => set(state => { state.floors = state.floors.filter(f => f.floorUuid !== uuid); }), removePoint: (pointUuid) => { const removedFloors: Floor[] = []; const updatedFloors: Floor[] = []; set(state => { for (const floor of state.floors) { const pointIndex = floor.points.findIndex(p => p.pointUuid === pointUuid); if (pointIndex === -1) { updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } const remainingPoints = floor.points.filter(p => p.pointUuid !== pointUuid); if (remainingPoints.length <= 2) { removedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } floor.points = remainingPoints; updatedFloors.push(JSON.parse(JSON.stringify(floor))); } state.floors = updatedFloors; }); return { removedFloors, updatedFloors }; }, removeFloorByPoints: ([pointA, pointB]) => { const removedFloors: Floor[] = []; const updatedFloors: Floor[] = []; set(state => { for (const floor of state.floors) { const indices = floor.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } const areAdjacent = Math.abs(idxA - idxB) === 1 || (idxA === 0 && idxB === floor.points.length - 1) || (idxB === 0 && idxA === floor.points.length - 1); if (!areAdjacent) { updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } const remainingPoints = floor.points.filter( p => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid ); if (remainingPoints.length > 2) { floor.points = remainingPoints; updatedFloors.push(JSON.parse(JSON.stringify(floor))); } else { removedFloors.push(JSON.parse(JSON.stringify(floor))); } } state.floors = updatedFloors; }); return { removedFloors, updatedFloors }; }, clearFloors: () => set(state => { state.floors = []; }), setPosition: (pointUuid, position) => { let updatedFloor: Floor[] = []; set((state) => { for (const floor of state.floors) { const point = floor.points.find((p) => p.pointUuid === pointUuid); if (point) { point.position = position; updatedFloor.push(JSON.parse(JSON.stringify(floor))); } } }); return updatedFloor; }, setIsBeveled: (uuid, isBeveled) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { floor.isBeveled = isBeveled; } }), setBevelStrength: (uuid, strength) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { floor.bevelStrength = strength; } }), setDepth: (uuid, depth) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { floor.floorDepth = depth; } }), setMaterial: (uuid, sideMaterial, topMaterial) => set(state => { const floor = state.floors.find(f => f.floorUuid === uuid); if (floor) { floor.sideMaterial = sideMaterial; floor.topMaterial = topMaterial; } }), addDecal: (floorUuid, decal) => set(state => { const floor = state.floors.find(f => f.floorUuid === floorUuid); if (floor) { floor.decals.push(decal); } }), updateDecal: (decalUuid, updatedDecal) => set(state => { for (const floor of state.floors) { const index = floor.decals.findIndex(d => d.decalUuid === decalUuid); if (index !== -1) { floor.decals[index] = updatedDecal; break; } } }), removeDecal: (decalUuid) => set(state => { for (const floor of state.floors) { floor.decals = floor.decals.filter(d => d.decalUuid !== decalUuid); } }), updateDecalPosition: (decalUuid, position) => set(state => { for (const floor of state.floors) { const decal = floor.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalPosition = position; break; } } }), updateDecalRotation: (decalUuid, rotation) => set(state => { for (const floor of state.floors) { const decal = floor.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalRotation = rotation; break; } } }), updateDecalScale: (decalUuid, scale) => set(state => { for (const floor of state.floors) { const decal = floor.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalScale = scale; break; } } }), getFloorById: (uuid) => { return get().floors.find(f => f.floorUuid === uuid); }, getFloorsByPointId: (pointUuid) => { return get().floors.filter(floor => { return floor.points.some(p => p.pointUuid === pointUuid); }); }, getFloorByPoints: (points) => { return get().floors.find(floor => { const floorPointIds = new Set(floor.points.map(p => p.pointUuid)); const givenPointIds = new Set(points.map(p => p.pointUuid)); return floorPointIds.size === givenPointIds.size && [...floorPointIds].every(id => givenPointIds.has(id)); }); }, getFloorPointById: (pointUuid) => { for (const floor of get().floors) { const point = floor.points.find(p => p.pointUuid === pointUuid); if (point) return point; } return undefined; }, getConnectedPoints: (pointUuid) => { const connected: Point[] = []; for (const floor of get().floors) { if (floor.points.some(p => p.pointUuid === pointUuid)) { connected.push(...floor.points.filter(p => p.pointUuid !== pointUuid)); } } return connected; } })) ); }; export type FloorStoreType = ReturnType;