diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx
index e7cc3db..d6413bc 100644
--- a/app/src/components/layout/sidebarRight/SideBarRight.tsx
+++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx
@@ -23,12 +23,14 @@ import {
useSelectedEventSphere,
} from "../../../store/simulation/useSimulationStore";
import GlobalProperties from "./properties/GlobalProperties";
-import AsstePropertiies from "./properties/AssetProperties";
+import AssetProperties from "./properties/AssetProperties";
import ZoneProperties from "./properties/ZoneProperties";
import EventProperties from "./properties/eventProperties/EventProperties";
import VersionHistory from "./versionHisory/VersionHistory";
import AisleProperties from "./properties/AisleProperties";
-import WallProperties from "./properties/eventProperties/WallProperties";
+import WallProperties from "./properties/WallProperties";
+import { useBuilderStore } from "../../../store/builder/useBuilderStore";
+import SelectedWallProperties from "./properties/SelectedWallProperties";
const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore();
@@ -36,6 +38,7 @@ const SideBarRight: React.FC = () => {
const { toolMode } = useToolMode();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
+ const { selectedWall } = useBuilderStore();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
@@ -143,7 +146,8 @@ const SideBarRight: React.FC = () => {
{!viewVersionHistory &&
subModule === "properties" &&
activeModule !== "visualization" &&
- !selectedFloorItem && (
+ !selectedFloorItem &&
+ !selectedWall && (
{(() => {
@@ -158,13 +162,26 @@ const SideBarRight: React.FC = () => {
)}
+
{!viewVersionHistory &&
subModule === "properties" &&
activeModule !== "visualization" &&
selectedFloorItem && (
+ )}
+
+ {!viewVersionHistory &&
+ subModule === "properties" &&
+ activeModule !== "visualization" &&
+ !selectedFloorItem &&
+ selectedWall && (
+
)}
@@ -178,6 +195,7 @@ const SideBarRight: React.FC = () => {
)}
+
{/* simulation */}
{!isVersionSaved &&
!viewVersionHistory &&
diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx
new file mode 100644
index 0000000..b647145
--- /dev/null
+++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx
@@ -0,0 +1,143 @@
+import { useState } from "react";
+import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
+
+import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
+import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
+
+import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
+import { useSceneContext } from "../../../../modules/scene/sceneContext";
+
+const SelectedWallProperties = () => {
+ const { selectedWall } = useBuilderStore();
+ const { wallStore } = useSceneContext();
+ const { getWallById, updateWall } = wallStore();
+
+ const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
+
+ const materials = [
+ { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
+ { texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
+ ];
+
+ const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null;
+
+ const handleHeightChange = (val: string) => {
+ const height = parseFloat(val);
+ if (!isNaN(height) && wall) {
+ updateWall(wall.wallUuid, { wallHeight: height });
+ }
+ };
+
+ const handleThicknessChange = (val: string) => {
+ const thickness = parseFloat(val);
+ if (!isNaN(thickness) && wall) {
+ updateWall(wall.wallUuid, { wallThickness: thickness });
+ }
+ };
+
+ const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
+ if (!wall) return;
+
+ const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
+
+ updateWall(wall.wallUuid, updated);
+ };
+
+ if (!wall) return null;
+
+ const selectedMaterials = {
+ side1: {
+ texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown',
+ textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown',
+ textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown'
+ },
+ side2: {
+ texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown',
+ textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown',
+ textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown'
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+ {(["side1", "side2"] as const).map((side) => (
+
+ ))}
+
+
+
+
![{selectedMaterials[activeSide].textureName}]({selectedMaterials[activeSide].texture})
+
+
+
+
+
+ {materials.map((material, index) => {
+ const isSelected = selectedMaterials[activeSide].textureId === material.textureId;
+
+ return (
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+export default SelectedWallProperties;
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx
similarity index 67%
rename from app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx
rename to app/src/components/layout/sidebarRight/properties/WallProperties.tsx
index f3cb792..eb835f1 100644
--- a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx
+++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx
@@ -1,11 +1,12 @@
import { useEffect, useState } from "react";
-import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
-import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
+import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
// Texture Imports
-import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png";
-import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg";
-import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
+
+import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
+import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
+
+import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
// Define Material type
type Material = {
@@ -58,14 +59,6 @@ const WallProperties = () => {
setWallThickness(parseFloat(newValue));
};
- const handleAddMaterial = () => {
- const newMaterial: Material = {
- texture: defaultMaterial.texture,
- textureName: `Material ${materials.length + 1}`,
- };
- setMaterials([...materials, newMaterial]);
- };
-
const handleSelectMaterial = (material: Material) => {
setSelectedMaterials((prev) => ({
...prev,
@@ -73,46 +66,26 @@ const WallProperties = () => {
}));
};
- const handleRemoveMaterial = (index: number) => {
- const removedTexture = materials[index].texture;
-
- const updatedMaterials = materials.filter((_, i) => i !== index);
- const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
- setMaterials(newMaterials);
-
- setSelectedMaterials((prev) => {
- const updated = { ...prev };
- ["side1", "side2"].forEach((side) => {
- if (updated[side as "side1" | "side2"]?.texture === removedTexture) {
- updated[side as "side1" | "side2"] = defaultMaterial;
- }
- });
- return updated;
- });
- };
-
return (
-
Wall
-
- handleHeightChange(val)}
- />
- handleThicknessChange(val)}
- />
-
-
+
+ Wall
+
+ handleHeightChange(val)}
+ />
+ handleThicknessChange(val)}
+ />
+
+
@@ -185,15 +158,6 @@ const WallProperties = () => {
{material.textureName}
-
);
})}
diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx
index b977781..cbbf2fe 100644
--- a/app/src/modules/builder/builder.tsx
+++ b/app/src/modules/builder/builder.tsx
@@ -276,7 +276,7 @@ export default function Builder() {
- {/* */}
+
>
);
}
diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx
index 8f1c2f2..ed3065d 100644
--- a/app/src/modules/builder/groups/floorPlanGroup.tsx
+++ b/app/src/modules/builder/groups/floorPlanGroup.tsx
@@ -148,7 +148,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
}
if (toolMode === "Wall") {
- drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',);
+ // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',);
}
if (toolMode === "Floor") {
diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx
index 68402d9..19f0810 100644
--- a/app/src/modules/builder/line/line.tsx
+++ b/app/src/modules/builder/line/line.tsx
@@ -1,11 +1,11 @@
import * as THREE from 'three';
+import { useThree } from '@react-three/fiber';
import { useEffect, useMemo, useState } from "react";
-import * as Constants from '../../../types/world/worldConstants';
import { DragControls, Tube } from '@react-three/drei';
import { useToolMode } from '../../../store/builder/store';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
-import { useWallStore } from '../../../store/builder/useWallStore';
-import { useThree } from '@react-three/fiber';
+import { useSceneContext } from '../../scene/sceneContext';
+import * as Constants from '../../../types/world/worldConstants';
interface LineProps {
points: [Point, Point];
@@ -17,7 +17,8 @@ function Line({ points }: Readonly) {
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isDeletable, setIsDeletable] = useState(false);
const { toolMode } = useToolMode();
- const { removeWallByPoints, setPosition } = useWallStore();
+ const { wallStore } = useSceneContext();
+ const { removeWallByPoints, setPosition } = wallStore();
const [dragOffset, setDragOffset] = useState(null);
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
@@ -79,6 +80,7 @@ function Line({ points }: Readonly) {
if (toolMode === '2D-Delete') {
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
removeWallByPoints(points);
+ setHoveredLine(null);
}
gl.domElement.style.cursor = 'default';
}
diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx
index 88c9890..c7d31cc 100644
--- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx
+++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx
@@ -1,6 +1,5 @@
import * as THREE from 'three';
import { useCallback } from 'react';
-import { useWallStore } from '../../../../store/builder/useWallStore';
import { useSceneContext } from '../../../scene/sceneContext';
const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
@@ -12,9 +11,9 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i
const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not
export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => {
- const { aisleStore } = useSceneContext();
+ const { aisleStore, wallStore } = useSceneContext();
const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore();
- const { walls, getConnectedPoints: getConnectedWallPoints } = useWallStore();
+ const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore();
// Wall Snapping
diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx
index 3545e99..a671806 100644
--- a/app/src/modules/builder/point/point.tsx
+++ b/app/src/modules/builder/point/point.tsx
@@ -6,7 +6,6 @@ import { DragControls } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { usePointSnapping } from './helpers/usePointSnapping';
-import { useWallStore } from '../../../store/builder/useWallStore';
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
import { useParams } from 'react-router-dom';
import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi';
@@ -20,9 +19,9 @@ function Point({ point }: { readonly point: Point }) {
const [isHovered, setIsHovered] = useState(false);
const [dragOffset, setDragOffset] = useState(null);
const { toolMode } = useToolMode();
- const { aisleStore } = useSceneContext();
+ const { aisleStore, wallStore } = useSceneContext();
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
- const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore();
+ const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore();
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
const { selectedVersionStore } = useVersionContext();
@@ -31,6 +30,10 @@ function Point({ point }: { readonly point: Point }) {
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
const colors = getColor(point);
+ useEffect(() => {
+ gl.domElement.style.cursor = 'default';
+ }, [toolMode])
+
function getColor(point: Point) {
if (point.pointType === 'Aisle') {
return {
diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx
index 6c2d858..4ada970 100644
--- a/app/src/modules/builder/wall/Instances/instance/wall.tsx
+++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx
@@ -1,18 +1,25 @@
import * as THREE from 'three';
+import { Base } from '@react-three/csg';
import { useMemo, useRef, useState } from 'react';
-import * as Constants from '../../../../../types/world/worldConstants';
+import { Decal, MeshDiscardMaterial } from '@react-three/drei';
+import { useFrame, useThree } from '@react-three/fiber';
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
-import { useWallStore } from '../../../../../store/builder/useWallStore';
+
+import useModuleStore from '../../../../../store/useModuleStore';
+import { useSceneContext } from '../../../../scene/sceneContext';
import { useWallClassification } from './helpers/useWallClassification';
-import { useFrame, useThree } from '@react-three/fiber';
-import { useWallVisibility } from '../../../../../store/builder/store';
-import { Decal } from '@react-three/drei';
-import { Base } from '@react-three/csg';
+import { useToggleView, useWallVisibility } from '../../../../../store/builder/store';
+import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
+import * as Constants from '../../../../../types/world/worldConstants';
function Wall({ wall }: { readonly wall: Wall }) {
- const { walls } = useWallStore();
+ const { wallStore } = useSceneContext();
+ const { walls } = wallStore();
+ const { togglView } = useToggleView();
+ const { setSelectedWall } = useBuilderStore();
+ const { activeModule } = useModuleStore();
const { camera } = useThree();
const { wallVisibility } = useWallVisibility();
const { getWallType, isWallFlipped } = useWallClassification(walls);
@@ -67,7 +74,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
new THREE.MeshStandardMaterial({
color: Constants.wallConfig.defaultColor,
side: THREE.DoubleSide,
- map: wall.outsideMaterial === 'Default Material`' ? defaultWallTexture : material1WallTexture,
+ map: wall.outsideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture,
}),
];
}, [defaultWallTexture, material1WallTexture, wall]);
@@ -100,6 +107,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
geometry={geometry}
position={[centerX, centerY, centerZ]}
rotation={[0, -angle, 0]}
+ userData={wall}
>
{materials.map((material, index) => (
@@ -112,6 +120,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
position={[decal.decalPosition[0], decal.decalPosition[1], wall.wallThickness / 2]}
rotation={[0, 0, decal.decalRotation]}
scale={[decal.decalScale, decal.decalScale, 0.001]}
+ userData={decal}
>
+ {
+ if (visible && !togglView && activeModule === 'builder') {
+ setSelectedWall(e.object)
+ }
+ }}
+ onPointerMissed={() => { setSelectedWall(null) }}
+ >
+
+
);
}
diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx
index 37f07e0..b22d0e6 100644
--- a/app/src/modules/builder/wall/Instances/wallInstances.tsx
+++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx
@@ -2,9 +2,10 @@ import React, { useEffect, useMemo } from 'react';
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
import { Geometry } from '@react-three/csg';
import { Html, Extrude } from '@react-three/drei';
-import { useWallStore } from '../../../../store/builder/useWallStore'
-import { useWallClassification } from './instance/helpers/useWallClassification';
+import { useLoader } from '@react-three/fiber';
+import { useSceneContext } from '../../../scene/sceneContext';
import { useToggleView } from '../../../../store/builder/store';
+import { useWallClassification } from './instance/helpers/useWallClassification';
import Line from '../../line/line';
import Point from '../../point/point';
import WallInstance from './instance/wallInstance';
@@ -12,10 +13,10 @@ import * as Constants from '../../../../types/world/worldConstants';
import texturePath from "../../../../assets/textures/floor/white.png";
import texturePathDark from "../../../../assets/textures/floor/black.png";
-import { useLoader } from '@react-three/fiber';
function WallInstances() {
- const { walls } = useWallStore();
+ const { wallStore } = useSceneContext();
+ const { walls } = wallStore();
const { rooms } = useWallClassification(walls)
const { toggleView } = useToggleView();
diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx
index 61af916..a136a41 100644
--- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx
+++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { useThree } from '@react-three/fiber';
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
import * as Constants from '../../../../types/world/worldConstants';
-import { useWallStore } from '../../../../store/builder/useWallStore';
+import { useSceneContext } from '../../../scene/sceneContext';
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
import ReferencePoint from '../../point/reference/referencePoint';
import ReferenceWall from './referenceWall';
@@ -16,7 +16,8 @@ function WallCreator() {
const { toolMode } = useToolMode();
const { activeLayer } = useActiveLayer();
const { socket } = useSocketStore();
- const { addWall, getWallPointById, removeWall, getWallByPoints } = useWallStore();
+ const { wallStore } = useSceneContext();
+ const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore();
const drag = useRef(false);
const isLeftMouseDown = useRef(false);
const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore();
diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx
index b3fe3c4..07ef700 100644
--- a/app/src/modules/builder/wall/wallGroup.tsx
+++ b/app/src/modules/builder/wall/wallGroup.tsx
@@ -1,7 +1,21 @@
+import { useEffect } from 'react';
+import { useToggleView } from '../../../store/builder/store'
+import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import WallCreator from './wallCreator/wallCreator'
import WallInstances from './Instances/wallInstances'
+import useModuleStore from '../../../store/useModuleStore';
function WallGroup() {
+ const { togglView } = useToggleView();
+ const { setSelectedWall } = useBuilderStore();
+ const { activeModule } = useModuleStore();
+
+ useEffect(() => {
+ if (togglView || activeModule !== 'builder') {
+ setSelectedWall(null);
+ }
+ }, [togglView, activeModule])
+
return (
<>
diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx
index 276f0bf..1b91386 100644
--- a/app/src/modules/scene/postProcessing/postProcessing.tsx
+++ b/app/src/modules/scene/postProcessing/postProcessing.tsx
@@ -15,7 +15,7 @@ export default function PostProcessing() {
const { selectedWallItem } = useSelectedWallItem();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventSphere } = useSelectedEventSphere();
- const { selectedAisle } = useBuilderStore();
+ const { selectedAisle, selectedWall } = useBuilderStore();
function flattenChildren(children: any[]) {
const allChildren: any[] = [];
@@ -40,6 +40,10 @@ export default function PostProcessing() {
// console.log('selectedAisle: ', selectedAisle);
}, [selectedAisle])
+ useEffect(() => {
+ // console.log('selectedWall: ', selectedWall);
+ }, [selectedWall])
+
return (
)}
+ {selectedWall && (
+
+ )}
{deletableFloorItem && (
createAssetStore(), []);
+ const wallAssetStore = useMemo(() => createWallAssetStore(), []);
+ const wallStore = useMemo(() => createWallStore(), []);
const aisleStore = useMemo(() => createAisleStore(), []);
+ const zoneStore = useMemo(() => createZoneStore(), []);
+ const floorStore = useMemo(() => createFloorStore(), []);
const eventStore = useMemo(() => createEventStore(), []);
const productStore = useMemo(() => createProductStore(), []);
@@ -58,7 +70,11 @@ export function SceneProvider({
const clearStores = useMemo(() => () => {
assetStore.getState().clearAssets();
+ wallAssetStore.getState().clearWallAssets();
+ wallStore.getState().clearWalls();
aisleStore.getState().clearAisles();
+ zoneStore.getState().clearZones();
+ floorStore.getState().clearFloors();
eventStore.getState().clearEvents();
productStore.getState().clearProducts();
materialStore.getState().clearMaterials();
@@ -67,12 +83,16 @@ export function SceneProvider({
conveyorStore.getState().clearConveyors();
vehicleStore.getState().clearVehicles();
storageUnitStore.getState().clearStorageUnits();
- }, [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]);
+ }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]);
const contextValue = useMemo(() => (
{
assetStore,
+ wallAssetStore,
+ wallStore,
aisleStore,
+ zoneStore,
+ floorStore,
eventStore,
productStore,
materialStore,
@@ -84,7 +104,7 @@ export function SceneProvider({
clearStores,
layout
}
- ), [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]);
+ ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]);
return (
diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts
index 086a020..f59ab54 100644
--- a/app/src/store/builder/useBuilderStore.ts
+++ b/app/src/store/builder/useBuilderStore.ts
@@ -3,74 +3,58 @@ import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface BuilderState {
- // Common properties
-
+ // Point & Line Interaction
hoveredPoint: Point | null;
snappedPoint: Point | null;
snappedPosition: [number, number, number] | null;
-
hoveredLine: [Point, Point] | null;
- // Wall
-
+ // Wall Settings
+ selectedWall: Object3D | null;
wallThickness: number;
wallHeight: number;
outsideMaterial: string;
insideMaterial: string;
- setWallThickness: (thickness: number) => void;
- setWallHeight: (height: number) => void;
- setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
-
- // Aisle
-
+ // Aisle General
selectedAisle: Object3D | null;
-
aisleType: AisleTypes;
aisleWidth: number;
aisleColor: AisleColors;
- // Dashed aisle properties
+ // Aisle Specific Styles
dashLength: number;
gapLength: number;
-
- // Dotted aisle properties
dotRadius: number;
-
- // Arrows aisle properties
aisleLength: number;
-
- // Junction aisle properties
isFlipped: boolean;
- // Setters for common properties
-
+ // Setters - Point/Line
setHoveredPoint: (point: Point | null) => void;
setSnappedPoint: (point: Point | null) => void;
setSnappedPosition: (position: [number, number, number] | null) => void;
-
setHoveredLine: (line: [Point, Point] | null) => void;
- setSelectedAisle: (aisle: Object3D | null) => void;
+ // Setters - Wall
+ setSelectedWall: (wall: Object3D | null) => void;
+ setWallThickness: (thickness: number) => void;
+ setWallHeight: (height: number) => void;
+ setWallMaterial: (material: string, side: 'inside' | 'outside') => void;
+ // Setters - Aisle General
+ setSelectedAisle: (aisle: Object3D | null) => void;
setAisleType: (type: AisleTypes) => void;
setAisleWidth: (width: number) => void;
setAisleColor: (color: AisleColors) => void;
- // Setters for dashed aisle
+ // Setters - Aisle Specific
setDashLength: (length: number) => void;
setGapLength: (length: number) => void;
-
- // Setters for dotted aisle
setDotRadius: (radius: number) => void;
-
- // Setters for arrows aisle
setAisleLength: (length: number) => void;
-
- // Setters for junction aisle
setIsFlipped: (isFlipped: boolean) => void;
- // Batch setters
+ // Batch Setters
setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void;
setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void;
setArrowsAisleProperties: (width: number, aisleLength: number, gapLength: number) => void;
@@ -79,20 +63,62 @@ interface BuilderState {
export const useBuilderStore = create()(
immer((set) => ({
- // Default values
-
+ // === Defaults ===
hoveredPoint: null,
snappedPoint: null,
snappedPosition: null,
-
hoveredLine: null,
- // Wall
-
+ selectedWall: null,
wallThickness: 0.5,
wallHeight: 7,
outsideMaterial: 'Default Material',
- insideMaterial: 'Default Material',
+ insideMaterial: 'Material 1',
+
+ selectedAisle: null,
+ aisleType: 'solid-aisle',
+ aisleWidth: 0.1,
+ aisleColor: 'yellow',
+
+ dashLength: 0.5,
+ gapLength: 0.3,
+ dotRadius: 0.1,
+ aisleLength: 0.6,
+ isFlipped: false,
+
+ // === Setters: Point/Line ===
+
+ setHoveredPoint: (point: Point | null) => {
+ set((state) => {
+ state.hoveredPoint = point;
+ });
+ },
+
+ setSnappedPoint: (point: Point | null) => {
+ set((state) => {
+ state.snappedPoint = point;
+ });
+ },
+
+ setSnappedPosition: (position: [number, number, number] | null) => {
+ set((state) => {
+ state.snappedPosition = position;
+ });
+ },
+
+ setHoveredLine: (line: [Point, Point] | null) => {
+ set((state) => {
+ state.hoveredLine = line;
+ })
+ },
+
+ // === Setters: Wall ===
+
+ setSelectedWall: (wall: Object3D | null) => {
+ set((state) => {
+ state.selectedWall = wall;
+ })
+ },
setWallThickness: (thickness: number) => {
set((state) => {
@@ -113,44 +139,7 @@ export const useBuilderStore = create()(
});
},
- // Aisle
-
- selectedAisle: null,
-
- aisleType: 'solid-aisle',
- aisleWidth: 0.1,
- aisleColor: 'yellow',
- dashLength: 0.5,
- gapLength: 0.3,
- dotRadius: 0.1,
- aisleLength: 0.6,
- isFlipped: false,
-
- // Individual setters
-
- setHoveredPoint: (point: Point | null) => {
- set((state) => {
- state.hoveredPoint = point;
- });
- },
-
- setHoveredLine: (line: [Point, Point] | null) => {
- set((state) => {
- state.hoveredLine = line;
- })
- },
-
- setSnappedPoint: (point: Point | null) => {
- set((state) => {
- state.snappedPoint = point;
- });
- },
-
- setSnappedPosition: (position: [number, number, number] | null) => {
- set((state) => {
- state.snappedPosition = position;
- });
- },
+ // === Setters: Aisle General ===
setSelectedAisle: (aisle: Object3D | null) => {
set((state) => {
@@ -163,73 +152,78 @@ export const useBuilderStore = create()(
state.aisleType = type;
});
},
+
setAisleWidth: (width) => {
set((state) => {
state.aisleWidth = width;
});
},
+
setAisleColor: (color) => {
set((state) => {
state.aisleColor = color;
});
},
+
+ // === Setters: Aisle Specific ===
+
setDashLength: (length) => {
set((state) => {
state.dashLength = length;
});
},
+
setGapLength: (length) => {
set((state) => {
state.gapLength = length;
});
},
+
setDotRadius: (radius) => {
set((state) => {
state.dotRadius = radius;
});
},
+
setAisleLength: (length) => {
set((state) => {
state.aisleLength = length;
});
},
+
setIsFlipped: (isFlipped) => {
set((state) => {
state.isFlipped = isFlipped;
});
},
- // Batch setters
- setDashedAisleProperties: (width, dashLength, gapLength) => {
- set((state) => {
- state.aisleType = 'dashed-aisle';
- state.aisleWidth = width;
- state.dashLength = dashLength;
- state.gapLength = gapLength;
- });
- },
- setDottedAisleProperties: (width, dotRadius, gapLength) => {
- set((state) => {
- state.aisleType = 'dotted-aisle';
- state.aisleWidth = width;
- state.dotRadius = dotRadius;
- state.gapLength = gapLength;
- });
- },
- setArrowsAisleProperties: (width, aisleLength, gapLength) => {
- set((state) => {
- state.aisleType = 'arrows-aisle';
- state.aisleWidth = width;
- state.aisleLength = aisleLength;
- state.gapLength = gapLength;
- });
- },
- setAisleProperties: (type, width, color) => {
- set((state) => {
- state.aisleType = type;
- state.aisleWidth = width;
- state.aisleColor = color;
- });
- }
+ // === Batch Setters ===
+
+ setDashedAisleProperties: (width, dashLength, gapLength) => set((state) => {
+ state.aisleType = 'dashed-aisle';
+ state.aisleWidth = width;
+ state.dashLength = dashLength;
+ state.gapLength = gapLength;
+ }),
+
+ setDottedAisleProperties: (width, dotRadius, gapLength) => set((state) => {
+ state.aisleType = 'dotted-aisle';
+ state.aisleWidth = width;
+ state.dotRadius = dotRadius;
+ state.gapLength = gapLength;
+ }),
+
+ setArrowsAisleProperties: (width, aisleLength, gapLength) => set((state) => {
+ state.aisleType = 'arrows-aisle';
+ state.aisleWidth = width;
+ state.aisleLength = aisleLength;
+ state.gapLength = gapLength;
+ }),
+
+ setAisleProperties: (type, width, color) => set((state) => {
+ state.aisleType = type;
+ state.aisleWidth = width;
+ state.aisleColor = color;
+ })
}))
-);
\ No newline at end of file
+);
diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts
new file mode 100644
index 0000000..4c89333
--- /dev/null
+++ b/app/src/store/builder/useFloorStore.ts
@@ -0,0 +1,90 @@
+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) => void;
+ removeFloor: (uuid: string) => void;
+ removePointFromFloors: (pointUuid: string) => void;
+ clearFloors: () => void;
+ 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;
+
+ getFloorById: (uuid: string) => Floor | undefined;
+}
+
+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) => set(state => {
+ const floor = state.floors.find(f => f.floorUuid === uuid);
+ if (floor) {
+ Object.assign(floor, updated);
+ }
+ }),
+
+ removeFloor: (uuid) => set(state => {
+ state.floors = state.floors.filter(f => f.floorUuid !== uuid);
+ }),
+
+ removePointFromFloors: (pointUuid) => set(state => {
+ for (const floor of state.floors) {
+ floor.points = floor.points.filter(p => p.pointUuid !== pointUuid);
+ }
+ }),
+
+ clearFloors: () => set(state => {
+ state.floors = [];
+ }),
+
+ 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;
+ }
+ }),
+
+ getFloorById: (uuid) => {
+ return get().floors.find(f => f.floorUuid === uuid);
+ },
+ }))
+ );
+};
+
+export type FloorStoreType = ReturnType;
\ No newline at end of file
diff --git a/app/src/store/builder/useWallAssetStore.ts b/app/src/store/builder/useWallAssetStore.ts
new file mode 100644
index 0000000..408aade
--- /dev/null
+++ b/app/src/store/builder/useWallAssetStore.ts
@@ -0,0 +1,82 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface WallAssetStore {
+ wallAssets: WallAsset[];
+ setWallAssets: (assets: WallAsset[]) => void;
+ addWallAsset: (asset: WallAsset) => void;
+ updateWallAsset: (uuid: string, updated: Partial) => void;
+ removeWallAsset: (uuid: string) => void;
+ clearWallAssets: () => void;
+
+ setVisibility: (uuid: string, isVisible: boolean) => void;
+ setLock: (uuid: string, isLocked: boolean) => void;
+ setOpacity: (uuid: string, opacity: number) => void;
+
+ getWallAssetById: (uuid: string) => WallAsset | undefined;
+ getAssetsByWall: (wallUuid: string) => WallAsset[];
+}
+
+export const createWallAssetStore = () => {
+ return create()(
+ immer((set, get) => ({
+ wallAssets: [],
+
+ setWallAssets: (assets) => set(state => {
+ state.wallAssets = assets;
+ }),
+
+ addWallAsset: (asset) => set(state => {
+ state.wallAssets.push(asset);
+ }),
+
+ updateWallAsset: (uuid, updated) => set(state => {
+ const asset = state.wallAssets.find(a => a.modelUuid === uuid);
+ if (asset) {
+ Object.assign(asset, updated);
+ }
+ }),
+
+ removeWallAsset: (uuid) => set(state => {
+ state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid);
+ }),
+
+ clearWallAssets: () => {
+ set(state => {
+ state.wallAssets = [];
+ })
+ },
+
+ setVisibility: (uuid, isVisible) => set(state => {
+ const asset = state.wallAssets.find(a => a.modelUuid === uuid);
+ if (asset) {
+ asset.isVisible = isVisible;
+ }
+ }),
+
+ setLock: (uuid, isLocked) => set(state => {
+ const asset = state.wallAssets.find(a => a.modelUuid === uuid);
+ if (asset) {
+ asset.isLocked = isLocked;
+ }
+ }),
+
+ setOpacity: (uuid, opacity) => set(state => {
+ const asset = state.wallAssets.find(a => a.modelUuid === uuid);
+ if (asset) {
+ asset.opacity = opacity;
+ }
+ }),
+
+ getWallAssetById: (uuid) => {
+ return get().wallAssets.find(a => a.modelUuid === uuid);
+ },
+
+ getAssetsByWall: (wallUuid) => {
+ return get().wallAssets.filter(a => a.wallUuid === wallUuid);
+ },
+ }))
+ );
+};
+
+export type WallAssetStoreType = ReturnType;
\ No newline at end of file
diff --git a/app/src/store/builder/useWallStore.ts b/app/src/store/builder/useWallStore.ts
new file mode 100644
index 0000000..3547330
--- /dev/null
+++ b/app/src/store/builder/useWallStore.ts
@@ -0,0 +1,211 @@
+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) => void;
+ removeWall: (uuid: string) => void;
+ clearWalls: () => void;
+ removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
+ addDecal: (wallUuid: 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;
+
+ removePoint: (pointUuid: string) => Wall[];
+ setPosition: (pointUuid: string, position: [number, number, number]) => void;
+ setLayer: (pointUuid: string, layer: number) => void;
+
+ getWallById: (uuid: string) => Wall | undefined;
+ getWallByPointId: (uuid: string) => Wall | undefined;
+ getWallByPoints: (points: Point[]) => Wall | undefined;
+ getWallPointById: (uuid: string) => Point | undefined;
+ getConnectedPoints: (uuid: string) => Point[];
+}
+
+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) => set((state) => {
+ const wall = state.walls.find(w => w.wallUuid === uuid);
+ if (wall) {
+ Object.assign(wall, updated);
+ }
+ }),
+
+ 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) => set((state) => {
+ for (const wall of state.walls) {
+ const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
+ if (decalToUpdate) {
+ Object.assign(decalToUpdate, decal);
+ }
+ }
+ }),
+
+ removeDecal: (decalUuid) => set((state) => {
+ for (const wall of state.walls) {
+ wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid);
+ }
+ }),
+
+ updateDecalPosition: (decalUuid, position) => set((state) => {
+ for (const wall of state.walls) {
+ const decal = wall.decals.find(d => d.decalUuid === decalUuid);
+ if (decal) {
+ decal.decalPosition = position;
+ break;
+ }
+ }
+ }),
+
+ 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) => set((state) => {
+ for (const wall of state.walls) {
+ const point = wall.points.find(p => p.pointUuid === pointUuid);
+ if (point) {
+ point.position = position;
+ }
+ }
+ }),
+
+ 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);
+ },
+
+ getWallByPointId: (uuid) => {
+ for (const wall of get().walls) {
+ if (wall.points.some(p => p.pointUuid === uuid)) {
+ return wall;
+ }
+ }
+ return undefined;
+ },
+
+ 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;
+ },
+ }))
+ )
+}
+
+export type WallStoreType = ReturnType;
\ No newline at end of file
diff --git a/app/src/store/builder/useWallStore.tsx b/app/src/store/builder/useWallStore.tsx
deleted file mode 100644
index 4f57849..0000000
--- a/app/src/store/builder/useWallStore.tsx
+++ /dev/null
@@ -1,200 +0,0 @@
-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) => void;
- removeWall: (uuid: string) => void;
- removeWallByPoints: (Points: [Point, Point]) => Wall | undefined;
- addDecal: (wallUuid: 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;
-
- removePoint: (pointUuid: string) => Wall[];
- setPosition: (pointUuid: string, position: [number, number, number]) => void;
- setLayer: (pointUuid: string, layer: number) => void;
-
- getWallById: (uuid: string) => Wall | undefined;
- getWallByPointId: (uuid: string) => Wall | undefined;
- getWallByPoints: (points: Point[]) => Wall | undefined;
- getWallPointById: (uuid: string) => Point | undefined;
- getConnectedPoints: (uuid: string) => Point[];
-}
-
-export const useWallStore = create()(
- immer((set, get) => ({
- walls: [],
-
- setWalls: (walls) => set((state) => {
- state.walls = walls;
- }),
-
- addWall: (wall) => set((state) => {
- state.walls.push(wall);
- }),
-
- updateWall: (uuid, updated) => set((state) => {
- const wall = state.walls.find(w => w.wallUuid === uuid);
- if (wall) {
- Object.assign(wall, updated);
- }
- }),
-
- removeWall: (uuid) => set((state) => {
- state.walls = state.walls.filter(w => w.wallUuid !== uuid);
- }),
-
- 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) => set((state) => {
- for (const wall of state.walls) {
- const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
- if (decalToUpdate) {
- Object.assign(decalToUpdate, decal);
- }
- }
- }),
-
- removeDecal: (decalUuid) => set((state) => {
- for (const wall of state.walls) {
- wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid);
- }
- }),
-
- updateDecalPosition: (decalUuid, position) => set((state) => {
- for (const wall of state.walls) {
- const decal = wall.decals.find(d => d.decalUuid === decalUuid);
- if (decal) {
- decal.decalPosition = position;
- break;
- }
- }
- }),
-
- 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) => set((state) => {
- for (const wall of state.walls) {
- const point = wall.points.find(p => p.pointUuid === pointUuid);
- if (point) {
- point.position = position;
- }
- }
- }),
-
- 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);
- },
-
- getWallByPointId: (uuid) => {
- for (const wall of get().walls) {
- if (wall.points.some(p => p.pointUuid === uuid)) {
- return wall;
- }
- }
- return undefined;
- },
-
- 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;
- },
- }))
-);
diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts
new file mode 100644
index 0000000..ee3c736
--- /dev/null
+++ b/app/src/store/builder/useZoneStore.ts
@@ -0,0 +1,74 @@
+import { create } from 'zustand';
+import { immer } from 'zustand/middleware/immer';
+
+interface ZoneStore {
+ zones: Zone[];
+ setZones: (zones: Zone[]) => void;
+ addZone: (zone: Zone) => void;
+ updateZone: (uuid: string, updated: Partial) => void;
+ removeZone: (uuid: string) => void;
+ removePointFromZones: (pointUuid: string) => void;
+ clearZones: () => void;
+ setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void;
+ setColor: (uuid: string, color: string) => void;
+
+ getZoneById: (uuid: string) => Zone | undefined;
+}
+
+export const createZoneStore = () => {
+ return create()(
+ immer((set, get) => ({
+ zones: [],
+
+ setZones: (zones) => set(state => {
+ state.zones = zones;
+ }),
+
+ addZone: (zone) => set(state => {
+ state.zones.push(zone);
+ }),
+
+ updateZone: (uuid, updated) => set(state => {
+ const zone = state.zones.find(z => z.zoneUuid === uuid);
+ if (zone) {
+ Object.assign(zone, updated);
+ }
+ }),
+
+ removeZone: (uuid) => set(state => {
+ state.zones = state.zones.filter(z => z.zoneUuid !== uuid);
+ }),
+
+ removePointFromZones: (pointUuid) => set(state => {
+ for (const zone of state.zones) {
+ zone.points = zone.points.filter(p => p.pointUuid !== pointUuid);
+ }
+ }),
+
+ clearZones: () => set(state => {
+ state.zones = [];
+ }),
+
+ setViewPort: (uuid, position, target) => set(state => {
+ const zone = state.zones.find(z => z.zoneUuid === uuid);
+ if (zone) {
+ zone.viewPortPosition = position;
+ zone.viewPortTarget = target;
+ }
+ }),
+
+ setColor: (uuid, color) => set(state => {
+ const zone = state.zones.find(z => z.zoneUuid === uuid);
+ if (zone) {
+ zone.zoneColor = color;
+ }
+ }),
+
+ getZoneById: (uuid) => {
+ return get().zones.find(z => z.zoneUuid === uuid);
+ },
+ }))
+ );
+};
+
+export type ZoneStoreType = ReturnType;
\ No newline at end of file
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index 51f32df..6b24256 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -1657,8 +1657,13 @@
.sidebar-right-wrapper {
.wall-properties-container {
+ .wall-properties-section{
+ padding: 14px;
+ padding-bottom: 0;
+ margin-bottom: 8px;
+ }
.header {
- color: var(--background-color-button);
+ color: var(--text-color);
}
.wall-properties {
@@ -1692,7 +1697,7 @@
flex-direction: column;
align-items: center;
gap: 15px;
- background: var(--Grays-Gray-6, #f2f2f7);
+ background: var(--background-color-secondary);
padding: 18px 25px;
.sides-wrapper {
@@ -1736,8 +1741,10 @@
}
.preview {
- width: 90%;
+ width: 100%;
height: 111px;
+ border-radius: 20px;
+ overflow: hidden;
img {
width: 100%;
@@ -1750,7 +1757,8 @@
.materials {
max-height: 250px;
overflow: auto;
- margin-bottom: 6px;
+ margin-top: 12px;
+ margin-bottom: 16px;
padding: 0 12px;
.material-container {