import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; interface WallStore { walls: Wall[]; setWalls: (walls: Wall[]) => void; addWall: (wall: Wall) => void; updateWall: (uuid: string, updated: Partial) => Wall | undefined; removeWall: (uuid: string) => void; clearWalls: () => void; removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; addDecal: (wallUuid: string, decal: Decal) => void; updateDecal: (decalUuid: string, decal: Decal) => Wall | undefined; removeDecal: (decalUuid: string) => Wall | undefined; updateDecalPosition: (decalUuid: string, position: [number, number, number]) => Wall | undefined; updateDecalRotation: (decalUuid: string, rotation: number) => void; updateDecalScale: (decalUuid: string, scale: number) => void; removePoint: (pointUuid: string) => Wall[]; setPosition: (pointUuid: string, position: [number, number, number]) => Wall[] | []; setLayer: (pointUuid: string, layer: number) => void; getWallById: (uuid: string) => Wall | undefined; getWallsByPointId: (uuid: string) => Wall[] | []; getWallByPoints: (points: Point[]) => Wall | undefined; getWallPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; getConnectedWallsByWallId: (wallUuid: string, skipSelf: boolean) => Wall[]; } export const createWallStore = () => { return create()( immer((set, get) => ({ walls: [], setWalls: (walls) => set((state) => { state.walls = walls; }), addWall: (wall) => set((state) => { state.walls.push(wall); }), updateWall: (uuid, updated) => { let updatedWall: Wall | undefined; set((state) => { const wall = state.walls.find(w => w.wallUuid === uuid); if (wall) { Object.assign(wall, updated); updatedWall = JSON.parse(JSON.stringify(wall)); } }); return updatedWall; }, removeWall: (uuid) => set((state) => { state.walls = state.walls.filter(w => w.wallUuid !== uuid); }), clearWalls: () => { set((state) => { state.walls = []; }) }, removeWallByPoints: (points) => { let removedWall: Wall | undefined; const [pointA, pointB] = points; set((state) => { state.walls = state.walls.filter(wall => { const wallPoints = wall.points.map(p => p.pointUuid); const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid); if (hasBothPoints) { removedWall = JSON.parse(JSON.stringify(wall)); return false; } return true; }); }); return removedWall; }, addDecal: (wallUuid, decal) => set((state) => { const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid); if (wallToUpdate) { wallToUpdate.decals.push(decal); } }), updateDecal: (decalUuid, decal) => { let affectedWall: Wall | undefined; set((state) => { for (const wall of state.walls) { const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid); if (decalToUpdate) { Object.assign(decalToUpdate, decal); affectedWall = JSON.parse(JSON.stringify(wall)); } } }); return affectedWall; }, removeDecal: (decalUuid) => { let affectedWall: Wall | undefined; set((state) => { for (const wall of state.walls) { const hasDecal = wall.decals.some(d => d.decalUuid === decalUuid); if (hasDecal) { wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid); affectedWall = JSON.parse(JSON.stringify(wall)); } } }); return affectedWall; }, updateDecalPosition: (decalUuid, position) => { let affectedWall: Wall | undefined; set((state) => { for (const wall of state.walls) { const decal = wall.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalPosition = position; affectedWall = JSON.parse(JSON.stringify(wall)); break; } } }) return affectedWall; }, updateDecalRotation: (decalUuid, rotation) => set((state) => { for (const wall of state.walls) { const decal = wall.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalRotation = rotation; break; } } }), updateDecalScale: (decalUuid, scale) => set((state) => { for (const wall of state.walls) { const decal = wall.decals.find(d => d.decalUuid === decalUuid); if (decal) { decal.decalScale = scale; break; } } }), removePoint: (pointUuid) => { const removedWalls: Wall[] = []; set((state) => { state.walls = state.walls.filter((wall) => { const hasPoint = wall.points.some(p => p.pointUuid === pointUuid); if (hasPoint) { removedWalls.push(JSON.parse(JSON.stringify(wall))); return false; } return true; }); }); return removedWalls; }, setPosition: (pointUuid, position) => { let updatedWalls: Wall[] = []; set((state) => { for (const wall of state.walls) { const point = wall.points.find(p => p.pointUuid === pointUuid); if (point) { point.position = position; updatedWalls.push(wall); } } }); return updatedWalls; }, setLayer: (pointUuid, layer) => set((state) => { for (const wall of state.walls) { const point = wall.points.find(p => p.pointUuid === pointUuid); if (point) { point.layer = layer; } } }), getWallById: (uuid) => { return get().walls.find(w => w.wallUuid === uuid); }, getWallsByPointId: (uuid) => { return get().walls.filter((a) => { return JSON.parse(JSON.stringify(a.points.some((p) => p.pointUuid === uuid))); }) }, getWallByPoints: (point) => { for (const wall of get().walls) { if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) && ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) { return wall; } } return undefined; }, getWallPointById: (uuid) => { for (const wall of get().walls) { const point = wall.points.find(p => p.pointUuid === uuid); if (point) return point; } return undefined; }, getConnectedPoints: (uuid) => { const connected: Point[] = []; for (const wall of get().walls) { for (const point of wall.points) { if (point.pointUuid === uuid) { connected.push(...wall.points.filter(p => p.pointUuid !== uuid)); } } } return connected; }, getConnectedWallsByWallId: (wallUuid, skipSelf) => { const wall = get().walls.find(w => w.wallUuid === wallUuid); if (!wall) return []; const pointUuids = wall.points.map(p => p.pointUuid); return get().walls.filter(w => { if (skipSelf && w.wallUuid === wallUuid) return false; return w.points.some(p => pointUuids.includes(p.pointUuid)); }); }, })) ) } export type WallStoreType = ReturnType;