Files
Dwinzo_Demo/app/src/store/builder/useFloorStore.ts

287 lines
11 KiB
TypeScript

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>) => 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<FloorStore>()(
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<typeof createFloorStore>;