diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 1bb6996..e0d5904 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -32,13 +32,13 @@ type DisplayComponent = | "aisleProperties" | "wallProperties" | "floorProperties" + | "zoneProperties" | "assetProperties" | "selectedWallProperties" | "selectedFloorProperties" | "selectedDecalProperties" | "selectedAisleProperties" | "selectedZoneProperties" - | "zoneProperties" | "simulations" | "mechanics" | "analysis" @@ -140,7 +140,7 @@ const SideBarRight: React.FC = () => { setDisplayComponent("selectedZoneProperties"); return; } - if (selectedAssets.length !== 1 && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) { + if (selectedAssets.length !== 1 && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle && !selectedZone) { if (toolMode === "Aisle") { setDisplayComponent("aisleProperties"); return; @@ -153,16 +153,16 @@ const SideBarRight: React.FC = () => { setDisplayComponent("floorProperties"); return; } + if (toolMode === "Zone") { + setDisplayComponent("zoneProperties"); + return; + } + setDisplayComponent("globalProperties"); return; } } - if (subModule === "zoneProperties" && (activeModule === "builder" || activeModule === "simulation")) { - setDisplayComponent("zoneProperties"); - return; - } - setDisplayComponent("none"); }, [viewVersionHistory, activeModule, subModule, isComparing, selectedAssets, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal, selectedZone]); diff --git a/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx b/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx index c5938f7..ffdf2f7 100644 --- a/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/FloorProperties.tsx @@ -2,11 +2,11 @@ import { useEffect, useState } from "react"; import InputToggle from "../../../ui/inputs/InputToggle"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import defaultTexture from '../../../../assets/textures/floor/white.png'; -import flootTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; -import flootTexture2 from '../../../../assets/textures/floor/tex1/MI_FactoryConcreteFloor01_BaseColor.001.jpg'; -import flootTexture3 from '../../../../assets/textures/floor/tex2/MI_FloorMats01_baseColor.png'; -import flootTexture4 from '../../../../assets/textures/floor/tex3/metal_plate_diff_1k.jpg'; +import defaultTexture from "../../../../assets/textures/floor/white.png"; +import flootTexture1 from "../../../../assets/textures/floor/factory wall texture.jpg"; +import flootTexture2 from "../../../../assets/textures/floor/tex1/MI_FactoryConcreteFloor01_BaseColor.001.jpg"; +import flootTexture3 from "../../../../assets/textures/floor/tex2/MI_FloorMats01_baseColor.png"; +import flootTexture4 from "../../../../assets/textures/floor/tex3/metal_plate_diff_1k.jpg"; import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; @@ -29,7 +29,7 @@ const FloorProperties = () => { const [activeSurface, setActiveSurface] = useState<"top" | "side">("top"); - const [selectedMaterials, setSelectedMaterials] = useState<{ top: Material | null; side: Material | null; }>({ top: null, side: null, }); + const [selectedMaterials, setSelectedMaterials] = useState<{ top: Material | null; side: Material | null }>({ top: null, side: null }); useEffect(() => { setSelectedMaterials({ @@ -61,30 +61,11 @@ const FloorProperties = () => { return (
-
Floor
+
Properties
- - handleIsBevelChange(!isBeveled)} - /> - + + handleIsBevelChange(!isBeveled)} /> +
@@ -95,47 +76,19 @@ const FloorProperties = () => {
- -
- {selectedMaterials[activeSurface] && ( - {selectedMaterials[activeSurface]!.textureName} - )} + {selectedMaterials[activeSurface] && {selectedMaterials[activeSurface]!.textureName}}
@@ -155,11 +108,7 @@ const FloorProperties = () => { >
- {material.textureName} + {material.textureName}
{material.textureName}
diff --git a/app/src/components/layout/sidebarRight/properties/SelectedZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedZoneProperties.tsx index e1d3832..27d2115 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedZoneProperties.tsx @@ -2,6 +2,8 @@ import { useState } from "react"; import { useParams } from "react-router-dom"; import { ArrowIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; +import RenameInput from "../../../ui/inputs/RenameInput"; +import Vector3Input from "../customInput/Vector3Input"; import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; import { useSocketStore } from "../../../../store/socket/useSocketStore"; @@ -17,10 +19,10 @@ interface TextureList { } export const zoneTextureList: TextureList[] = [ - { color: "blue", id: "#0000ff", zoneType: "" }, - { color: "red", id: "#ff0000", zoneType: "" }, + { color: "blue", id: "#0000FF", zoneType: "" }, + { color: "red", id: "#FF0000", zoneType: "" }, { color: "yellow", id: "#FBE50E", zoneType: "" }, - { color: "white", id: "#ffffff", zoneType: "" }, + { color: "white", id: "#FFFFFF", zoneType: "" }, { color: "green", id: "#43C06D", zoneType: "" }, { color: "orange", id: "#FF711B", zoneType: "" }, { color: "purple", id: "#AF52DE", zoneType: "" }, @@ -28,7 +30,7 @@ export const zoneTextureList: TextureList[] = [ function SelectedZoneProperties() { const { projectId } = useParams(); - const { selectedZone } = useBuilderStore(); + const { selectedZone, editZoneViewPort, setEditZoneViewPort, zoneViewPort } = useBuilderStore(); const { zoneStore, versionStore } = useSceneContext(); const { selectedVersion } = versionStore(); const { builderSocket } = useSocketStore(); @@ -90,13 +92,45 @@ function SelectedZoneProperties() { updateZoneToBackend(updatedZone); }; + const handleZoneNameCHange = (newName: string) => { + const updatedZone = peekUpdateZone(selectedZone.zoneData.zoneUuid, { zoneName: newName }); + updateZoneToBackend(updatedZone); + }; + + const handleSetView = () => { + if (zoneViewPort) { + setEditZoneViewPort(false); + const updatedZone = peekUpdateZone(selectedZone.zoneData.zoneUuid, { + viewPortPosition: [zoneViewPort.position.x, zoneViewPort.position.y, zoneViewPort.position.z], + viewPortTarget: [zoneViewPort.target.x, zoneViewPort.target.y, zoneViewPort.target.z], + }); + updateZoneToBackend(updatedZone); + } + }; + return (
Zone Properties
+
+
+ +
setEditZoneViewPort(!editZoneViewPort)}> + {editZoneViewPort ? "Cancel" : "Edit"} +
+
+ {}} header="Viewport Target" value={selectedZone.zoneData.viewPortTarget} disabled={!editZoneViewPort} /> + {}} header="Viewport Position" value={selectedZone.zoneData.viewPortPosition} disabled={!editZoneViewPort} /> + + {editZoneViewPort && ( +
+ Set View +
+ )} +
+ {/* Basic Properties */}
-
{selectedZone.zoneData.zoneName}
diff --git a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx index e158b44..a0e4ada 100644 --- a/app/src/components/layout/sidebarRight/properties/WallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx @@ -58,7 +58,7 @@ const WallProperties = () => { return (
-
Wall
+
Properties
{ - const { Edit, setEdit } = useEditPosition(); - const { selectedZone, setSelectedZone } = useSelectedZoneStore(); - const { zonePosition, setZonePosition } = usezonePosition(); - const { zoneTarget, setZoneTarget } = usezoneTarget(); - const { zoneStore, versionStore } = useSceneContext(); - const { selectedVersion } = versionStore(); - const { zones, setZoneName } = zoneStore() +export const zoneTextureList: TextureList[] = [ + { color: "blue", id: "#0000FF", zoneType: "" }, + { color: "red", id: "#FF0000", zoneType: "" }, + { color: "yellow", id: "#FBE50E", zoneType: "" }, + { color: "white", id: "#FFFFFF", zoneType: "" }, + { color: "green", id: "#43C06D", zoneType: "" }, + { color: "orange", id: "#FF711B", zoneType: "" }, + { color: "purple", id: "#AF52DE", zoneType: "" }, +]; - const { projectId } = useParams(); - const { organization } = getUserData(); +function ZoneProperties() { + const { zoneHeight, zoneColor, setZoneHeight, setZoneColor } = useBuilderStore(); + const [collapseTexture, setCollapseTexture] = useState(true); - useEffect(() => { - setZonePosition(selectedZone.zoneViewPortPosition); - setZoneTarget(selectedZone.zoneViewPortTarget); - }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]); - - async function handleSetView() { - try { - - let zonesdata = { - zoneUuid: selectedZone.zoneUuid, - viewPortPosition: zonePosition, - viewPortTarget: zoneTarget, - }; - - - let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || ""); - // - if (response.message === "zone updated") { - setEdit(false); - } else { - // - } - } catch (error) { - echo.error("Failed to set zone view"); - } - } - - function handleEditView() { - setEdit(!Edit); // This will toggle the `Edit` state correctly - } - - async function handleZoneNameChange(newName: string) { - const zonesdata = { - zoneUuid: selectedZone.zoneUuid, - zoneName: newName, + const handleHeightChange = (val: string) => { + const height = parseFloat(val); + if (!isNaN(height)) { + setZoneHeight(height); + } }; - // Call your API to update the zone - let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || ""); - if (response.message === "zone updated") { - setSelectedZone((prev) => ({ ...prev, zoneName: newName })); - setZoneName(selectedZone.zoneUuid, newName) - // setZones((prevZones: any[]) => - // prevZones.map((zone) => - // zone.zoneUuid === selectedZone.zoneUuid - // ? { ...zone, zoneName: newName } - // : zone - // ) - // ); - } else { - // - } - } - function handleVectorChange( - key: "zoneViewPortTarget" | "zoneViewPortPosition", - newValue: [number, number, number] - ) { - setSelectedZone((prev) => ({ ...prev, [key]: newValue })); - } - const checkZoneNameDuplicate = (name: string) => { - return zones.some( - (zone: any) => - zone.zoneName?.trim().toLowerCase() === name?.trim().toLowerCase() && - zone.zoneUuid !== selectedZone.zoneUuid - ); - }; + const handleColorChange = (val: string) => { + setZoneColor(val); + }; - return ( -
-
-
- -
- {Edit ? "Cancel" : "Edit"} -
+ return ( +
+
Properties
+ + {/* Basic Properties */} +
+
+ +
+
+ {/* Texture */} +
+ + + {collapseTexture && ( +
+ {zoneTextureList.map((val) => ( + + ))} + handleColorChange(e.target.value)} /> +
+ )} +
- handleVectorChange("zoneViewPortTarget", value)} - header="Viewport Target" - value={zoneTarget as [number, number, number]} - disabled={!Edit} - /> - - handleVectorChange("zoneViewPortPosition", value) - } - header="Viewport Position" - value={zonePosition as [number, number, number]} - disabled={!Edit} - /> - - {Edit && ( -
- Set View -
- )} -
-
- ); -}; + ); +} export default ZoneProperties; diff --git a/app/src/functions/outlineHelpers/useZoneAssetHandlers.ts b/app/src/functions/outlineHelpers/useZoneAssetHandlers.ts index d934cc6..6cbc134 100644 --- a/app/src/functions/outlineHelpers/useZoneAssetHandlers.ts +++ b/app/src/functions/outlineHelpers/useZoneAssetHandlers.ts @@ -26,7 +26,6 @@ export const useZoneAssetHandlers = () => { const handleSelectZone = useCallback( async (id: string) => { if (selectedZone?.zoneUuid === id || id === "unassigned-zone") return; - setSubModule("zoneProperties"); const response = await getZoneData(id, organization, projectId, selectedVersion?.versionId || ""); if (!response) return; diff --git a/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx index b453493..eba7274 100644 --- a/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx +++ b/app/src/modules/builder/zone/Instances/Instance/zoneInstance.tsx @@ -1,5 +1,7 @@ -import { useRef } from "react"; +import { useEffect, useRef } from "react"; import { Group, Vector3 } from "three"; +import { useThree } from "@react-three/fiber"; +import { CameraControls } from "@react-three/drei"; import useModuleStore from "../../../../../store/ui/useModuleStore"; import { useToggleView } from "../../../../../store/builder/store"; import { useBuilderStore } from "../../../../../store/builder/useBuilderStore"; @@ -9,6 +11,7 @@ import PolygonMaterial from "../../../wrappers/materials/polygonMaterial"; import ZoneCornerReference from "./zoneCornerReference"; function ZoneInstance({ zone }: { readonly zone: Zone }) { + const { controls }: { controls: CameraControls } = useThree(); const { toggleView } = useToggleView(); const { activeModule } = useModuleStore(); const { selectedZone, setSelectedZone } = useBuilderStore(); diff --git a/app/src/modules/builder/zone/Instances/zoneInstances.tsx b/app/src/modules/builder/zone/Instances/zoneInstances.tsx index bb30455..e979cdf 100644 --- a/app/src/modules/builder/zone/Instances/zoneInstances.tsx +++ b/app/src/modules/builder/zone/Instances/zoneInstances.tsx @@ -1,8 +1,10 @@ import React, { useEffect, useMemo } from "react"; import { Vector3 } from "three"; -import { Html } from "@react-three/drei"; +import { useFrame, useThree } from "@react-three/fiber"; +import { CameraControls, Html } from "@react-three/drei"; import { useSceneContext } from "../../../scene/sceneContext"; import { useToggleView } from "../../../../store/builder/store"; +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import Line from "../../line/line"; import Point from "../../point/point"; import ZoneInstance from "./Instance/zoneInstance"; @@ -10,13 +12,31 @@ import Zone2DInstance from "./Instance/zone2DInstance"; function ZoneInstances() { const { zoneStore } = useSceneContext(); + const { controls }: { controls: CameraControls } = useThree(); const { zones } = zoneStore(); const { toggleView } = useToggleView(); + const { selectedZone, editZoneViewPort, setZoneViewPort, zoneViewPort } = useBuilderStore(); useEffect(() => { // console.log('zones: ', zones); }, [zones]); + useEffect(() => { + if (selectedZone) { + controls.setLookAt(...selectedZone.zoneData.viewPortPosition, ...selectedZone.zoneData.viewPortTarget, true); + } + }, [selectedZone?.zoneMesh]); + + useFrame(() => { + if (editZoneViewPort) { + const position = controls.getPosition(new Vector3()); + const target = controls.getTarget(new Vector3()); + setZoneViewPort({ position, target }); + } else if (!editZoneViewPort && zoneViewPort) { + setZoneViewPort(null); + } + }); + const allPoints = useMemo(() => { const points: Point[] = []; const seenUuids = new Set(); diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index b65a16e..4851aed 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -34,6 +34,8 @@ interface BuilderState { // Zone Settings selectedZone: { zoneMesh: Object3D | null; zoneData: Zone } | null; + editZoneViewPort: boolean; + zoneViewPort: { position: Vector3; target: Vector3 } | null; zoneHeight: number; zoneColor: string; @@ -95,6 +97,8 @@ interface BuilderState { // Setters - Zone setSelectedZone: (zone: { zoneMesh: Object3D | null; zoneData: Zone } | null) => void; + setEditZoneViewPort: (edit: boolean) => void; + setZoneViewPort: (viewPort: { position: Vector3; target: Vector3 } | null) => void; setZoneHeight: (height: number) => void; setZoneColor: (color: string) => void; @@ -153,8 +157,10 @@ export const useBuilderStore = create()( topMaterial: "Default Material", selectedZone: null, + editZoneViewPort: false, + zoneViewPort: null, zoneHeight: 7, - zoneColor: "blue", + zoneColor: "#0000FF", selectedDecal: null, deletableDecal: null, @@ -298,6 +304,18 @@ export const useBuilderStore = create()( }); }, + setEditZoneViewPort: (edit: boolean) => { + set((state) => { + state.editZoneViewPort = edit; + }); + }, + + setZoneViewPort: (viewPort: { position: Vector3; target: Vector3 } | null) => { + set((state) => { + state.zoneViewPort = viewPort; + }); + }, + setZoneHeight: (height: number) => { set((state) => { state.zoneHeight = height; diff --git a/app/src/store/ui/useModuleStore.ts b/app/src/store/ui/useModuleStore.ts index 8d70ad0..39c0c5b 100644 --- a/app/src/store/ui/useModuleStore.ts +++ b/app/src/store/ui/useModuleStore.ts @@ -14,7 +14,7 @@ export default useModuleStore; // New store for subModule -type SubModule = "properties" | "simulations" | "mechanics" | "analysis" | "zoneProperties" | "resourceManagement"; +type SubModule = "properties" | "simulations" | "mechanics" | "analysis" | "resourceManagement"; interface SubModuleStore { subModule: SubModule;