287 lines
11 KiB
TypeScript
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>; |