optimized old zustand store and post processing outlines

This commit is contained in:
2025-09-01 15:09:04 +05:30
parent 09c909c377
commit ef98b3c1a3
19 changed files with 1228 additions and 1440 deletions

View File

@@ -1,13 +1,12 @@
import React, { useEffect } from "react";
import {
useLoadingProgress,
useRenameModeStore,
useSaveVersion,
useSelectedAssets,
useSelectedComment,
useSelectedFloorItem,
useSocketStore,
useWidgetSubOption,
useLoadingProgress,
useRenameModeStore,
useSaveVersion,
useSelectedAssets,
useSelectedComment,
useSocketStore,
useWidgetSubOption,
} from "../../../store/builder/store";
import useModuleStore, { useThreeDStore } from "../../../store/useModuleStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
@@ -27,10 +26,7 @@ import ControlsPlayer from "../controls/ControlsPlayer";
import SelectFloorPlan from "../../temporary/SelectFloorPlan";
import { createHandleDrop } from "../../../modules/visualization/functions/handleUiDrop";
import Scene from "../../../modules/scene/scene";
import {
useComparisonProduct,
useMainProduct,
} from "../../../store/simulation/useSimulationStore";
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
import { useProductContext } from "../../../modules/simulation/products/productContext";
import RegularDropDown from "../../ui/inputs/RegularDropDown";
import RenameTooltip from "../../ui/features/RenameTooltip";
@@ -42,184 +38,173 @@ import { useVersionContext } from "../../../modules/builder/version/versionConte
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
import Footer from "../../footer/Footer";
import ThreadChat from "../../ui/collaboration/ThreadChat";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
function MainScene() {
const { setMainProduct } = useMainProduct();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
const { activeModule } = useModuleStore();
const { selectedUser } = useSelectedUserStore();
const { loadingProgress } = useLoadingProgress();
const { toggleThreeD } = useThreeDStore();
const { isPlaying } = usePlayButtonStore();
const { widgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore();
const { selectedZone } = useSelectedZoneStore();
const { setFloatingWidget } = useFloatingWidget();
const { clearComparisonProduct } = useComparisonProduct();
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { assetStore, productStore } = useSceneContext();
const { products } = productStore();
const { setName } = assetStore();
const { projectId } = useParams()
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
const { versionHistory } = useVersionHistoryStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
const { selectedComment, commentPositionState } = useSelectedComment();
const { setMainProduct } = useMainProduct();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
const { activeModule } = useModuleStore();
const { selectedUser } = useSelectedUserStore();
const { loadingProgress } = useLoadingProgress();
const { toggleThreeD } = useThreeDStore();
const { isPlaying } = usePlayButtonStore();
const { widgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore();
const { selectedZone } = useSelectedZoneStore();
const { setFloatingWidget } = useFloatingWidget();
const { clearComparisonProduct } = useComparisonProduct();
const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
const { assetStore, productStore } = useSceneContext();
const { products } = productStore();
const { setName } = assetStore();
const { projectId } = useParams()
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
const { versionHistory } = useVersionHistoryStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
const { selectedComment, commentPositionState } = useSelectedComment();
useEffect(() => {
if (activeModule !== 'simulation') {
clearComparisonProduct();
setIsVersionSaved(false);
}
}, [activeModule, clearComparisonProduct, setIsVersionSaved])
useEffect(() => {
if (versionHistory.length > 0) {
setSelectedVersion(versionHistory[0])
}
}, [setSelectedVersion, versionHistory])
const handleSelectVersion = (option: string) => {
const version = versionHistory.find((version) => version.versionName === option);
if (version) {
setSelectedVersion(version);
}
};
const handleSelectProduct = (option: string) => {
const product = products.find((product) => product.productName === option);
if (product) {
setMainProduct(product.productUuid, product.productName);
}
};
const handleObjectRename = async (newName: string) => {
if (!projectId) return
if (selectedFloorItem) {
console.log('selectedFloorItem.userData.modelUuid: ', selectedFloorItem.userData.modelUuid);
console.log(' newName: ', newName);
console.log('projectId: ', projectId);
setAssetsApi({
modelUuid: selectedFloorItem.userData.modelUuid,
modelName: newName,
projectId,
versionId: selectedVersion?.versionId || ''
}).then(() => {
selectedFloorItem.userData = {
...selectedFloorItem.userData,
modelName: newName
};
setSelectedFloorItem(selectedFloorItem);
setIsRenameMode(false);
setName(selectedFloorItem.userData.modelUuid, newName);
})
} else if (selectedAssets.length === 1) {
setAssetsApi({
modelUuid: selectedAssets[0].userData.modelUuid,
modelName: newName,
projectId,
versionId: selectedVersion?.versionId || ''
}).then(() => {
selectedAssets[0].userData = {
...selectedAssets[0].userData,
modelName: newName
};
setSelectedAssets(selectedAssets);
setIsRenameMode(false);
setName(selectedAssets[0].userData.modelUuid, newName);
})
}
}
return (
<>
{!selectedUser && (
<>
<KeyPressListener />
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
{!isPlaying && (
<>
{toggleThreeD && !isVersionSaved && <ModuleToggle />}
<SideBarLeft />
<SideBarRight />
</>
)}
<RealTimeVisulization />
{activeModule === "market" && <MarketPlace />}
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
<Tools />
)}
{(isPlaying) &&
activeModule === "simulation" &&
loadingProgress === 0 && <SimulationPlayer />}
{(isPlaying) &&
activeModule !== "simulation" && <ControlsPlayer />}
{isRenameMode && (selectedFloorItem?.userData.modelName || selectedAssets.length === 1) && <RenameTooltip name={selectedFloorItem?.userData.modelName || selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}
{/* remove this later */}
{activeModule === "builder" && !toggleThreeD && <SelectFloorPlan />}
</>
)}
<div
className="scene-container"
id="work-space-three-d-canvas"
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
role="application"
onDrop={(event) =>
createHandleDrop({
widgetSubOption,
visualizationSocket,
selectedZone,
setFloatingWidget,
event,
projectId,
versionId: selectedVersion?.versionId || '',
})
useEffect(() => {
if (activeModule !== 'simulation') {
clearComparisonProduct();
setIsVersionSaved(false);
}
onDragOver={(event) => event.preventDefault()}
>
<Scene layout="Main Layout" />
</div>
}, [activeModule, clearComparisonProduct, setIsVersionSaved])
{selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
<div className="selectLayout-wrapper">
<RegularDropDown
header={selectedVersion.versionName}
options={versionHistory.map((v) => v.versionName)} // Pass layout names as options
onSelect={handleSelectVersion}
search={false}
/>
<br />
<RegularDropDown
header={selectedProduct.productName}
options={products.map((l) => l.productName)} // Pass layout names as options
onSelect={handleSelectProduct}
search={false}
/>
</div>
)}
useEffect(() => {
if (versionHistory.length > 0) {
setSelectedVersion(versionHistory[0])
}
}, [setSelectedVersion, versionHistory])
{activeModule !== "market" && !selectedUser && <Footer />}
const handleSelectVersion = (option: string) => {
const version = versionHistory.find((version) => version.versionName === option);
if (version) {
setSelectedVersion(version);
}
};
<VersionSaved />
const handleSelectProduct = (option: string) => {
const product = products.find((product) => product.productName === option);
if (product) {
setMainProduct(product.productUuid, product.productName);
}
};
{
(commentPositionState !== null || selectedComment !== null) &&
<ThreadChat />
}
const handleObjectRename = async (newName: string) => {
if (!projectId) return
if (selectedFloorAsset) {
setAssetsApi({
modelUuid: selectedFloorAsset.userData.modelUuid,
modelName: newName,
projectId,
versionId: selectedVersion?.versionId || ''
}).then(() => {
selectedFloorAsset.userData = { ...selectedFloorAsset.userData, modelName: newName };
setSelectedFloorAsset(selectedFloorAsset);
setIsRenameMode(false);
setName(selectedFloorAsset.userData.modelUuid, newName);
})
} else if (selectedAssets.length === 1) {
setAssetsApi({
modelUuid: selectedAssets[0].userData.modelUuid,
modelName: newName,
projectId,
versionId: selectedVersion?.versionId || ''
}).then(() => {
selectedAssets[0].userData = { ...selectedAssets[0].userData, modelName: newName };
setSelectedAssets(selectedAssets);
setIsRenameMode(false);
setName(selectedAssets[0].userData.modelUuid, newName);
})
}
}
</>
);
return (
<>
{!selectedUser && (
<>
<KeyPressListener />
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
{!isPlaying && (
<>
{toggleThreeD && !isVersionSaved && <ModuleToggle />}
<SideBarLeft />
<SideBarRight />
</>
)}
<RealTimeVisulization />
{activeModule === "market" && <MarketPlace />}
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
<Tools />
)}
{(isPlaying) && activeModule === "simulation" && loadingProgress === 0 && <SimulationPlayer />}
{(isPlaying) && activeModule !== "simulation" && <ControlsPlayer />}
{isRenameMode && (selectedFloorAsset?.userData.modelName || selectedAssets.length === 1) && <RenameTooltip name={selectedFloorAsset?.userData.modelName || selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}
{/* remove this later */}
{activeModule === "builder" && !toggleThreeD && <SelectFloorPlan />}
</>
)}
<div
className="scene-container"
id="work-space-three-d-canvas"
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
role="application"
onDrop={(event) =>
createHandleDrop({
widgetSubOption,
visualizationSocket,
selectedZone,
setFloatingWidget,
event,
projectId,
versionId: selectedVersion?.versionId || '',
})
}
onDragOver={(event) => event.preventDefault()}
>
<Scene layout="Main Layout" />
</div>
{selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
<div className="selectLayout-wrapper">
<RegularDropDown
header={selectedVersion.versionName}
options={versionHistory.map((v) => v.versionName)} // Pass layout names as options
onSelect={handleSelectVersion}
search={false}
/>
<br />
<RegularDropDown
header={selectedProduct.productName}
options={products.map((l) => l.productName)} // Pass layout names as options
onSelect={handleSelectProduct}
search={false}
/>
</div>
)}
{activeModule !== "market" && !selectedUser && <Footer />}
<VersionSaved />
{
(commentPositionState !== null || selectedComment !== null) &&
<ThreadChat />
}
</>
);
}
export default MainScene;

View File

@@ -6,7 +6,7 @@ import { useToggleStore } from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import useVersionHistoryVisibleStore, { useSaveVersion, useSelectedFloorItem, useToolMode } from "../../../store/builder/store";
import useVersionHistoryVisibleStore, { useSaveVersion, useToolMode } from "../../../store/builder/store";
import { useSelectedEventData, useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
import GlobalProperties from "./properties/GlobalProperties";
@@ -48,8 +48,7 @@ const SideBarRight: React.FC = () => {
const { toggleUIRight } = useToggleStore();
const { toolMode } = useToolMode();
const { subModule, setSubModule } = useSubModuleStore();
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedWall, selectedFloor, selectedAisle } = useBuilderStore();
const { selectedWall, selectedFloor, selectedAisle, selectedFloorAsset } = useBuilderStore();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
@@ -108,31 +107,31 @@ const SideBarRight: React.FC = () => {
}
if (subModule === "properties" && activeModule !== "visualization") {
if (selectedFloorItem) {
if (selectedFloorAsset) {
setDisplayComponent("assetProperties");
return;
}
if (!selectedFloorItem && !selectedFloor && !selectedAisle && !selectedDecal && selectedWall) {
if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedDecal && selectedWall) {
setDisplayComponent("selectedWallProperties");
return;
}
if (!selectedFloorItem && !selectedWall && !selectedAisle && !selectedDecal && selectedFloor) {
if (!selectedFloorAsset && !selectedWall && !selectedAisle && !selectedDecal && selectedFloor) {
setDisplayComponent("selectedFloorProperties");
return;
}
if (viewVersionHistory && !selectedFloorItem && !selectedWall && !selectedAisle && !selectedFloor && !selectedDecal) {
if (viewVersionHistory && !selectedFloorAsset && !selectedWall && !selectedAisle && !selectedFloor && !selectedDecal) {
setDisplayComponent("versionHistory");
return;
}
if (!selectedFloorItem && !selectedFloor && !selectedAisle && !selectedWall && selectedDecal) {
if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedWall && selectedDecal) {
setDisplayComponent("selectedDecalProperties");
return;
}
if (!selectedFloorItem && !selectedFloor && !selectedWall && !selectedDecal && selectedAisle) {
if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && selectedAisle) {
setDisplayComponent("selectedAisleProperties");
return;
}
if (!selectedFloorItem && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) {
if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) {
if (toolMode === "Aisle") {
setDisplayComponent("aisleProperties");
return;
@@ -156,7 +155,7 @@ const SideBarRight: React.FC = () => {
}
setDisplayComponent("none");
}, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorItem, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
}, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorAsset, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
const renderComponent = () => {
switch (displayComponent) {

View File

@@ -4,143 +4,138 @@ import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
import PositionInput from "../customInput/PositionInputs";
import RotationInput from "../customInput/RotationInput";
import {
useSelectedFloorItem,
useObjectPosition,
useObjectRotation,
} from "../../../../store/builder/store";
import { useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
interface UserData {
id: number;
label: string;
value: string;
id: number;
label: string;
value: string;
}
const AssetProperties: React.FC = () => {
const [userData, setUserData] = useState<UserData[]>([]);
const { selectedFloorItem } = useSelectedFloorItem();
const { objectPosition } = useObjectPosition();
const { objectRotation } = useObjectRotation();
const { assetStore } = useSceneContext();
const { assets, setCurrentAnimation } = assetStore();
const { loopAnimation } = useBuilderStore();
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
const [userData, setUserData] = useState<UserData[]>([]);
const { objectPosition } = useObjectPosition();
const { objectRotation } = useObjectRotation();
const { assetStore } = useSceneContext();
const { assets, setCurrentAnimation } = assetStore();
const { loopAnimation, selectedFloorAsset } = useBuilderStore();
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
const handleAddUserData = () => {
setUserData([]);
};
const handleAddUserData = () => {
setUserData([]);
};
const handleUserDataChange = (id: number, newValue: string) => { };
const handleUserDataChange = (id: number, newValue: string) => { };
const handleRemoveUserData = (id: number) => { };
const handleRemoveUserData = (id: number) => { };
const handleAnimationClick = (animation: string) => {
if (selectedFloorItem) {
setCurrentAnimation(
selectedFloorItem.uuid,
animation,
true,
loopAnimation,
true
);
}
};
if (!selectedFloorItem) return null;
return (
<div className="asset-properties-container">
{/* Name */}
<div className="header">{selectedFloorItem.userData.modelName}</div>
<section>
{objectPosition && (
<PositionInput
disabled={true}
onChange={() => { }}
value1={parseFloat(objectPosition.x.toFixed(5))}
value2={parseFloat(objectPosition.z.toFixed(5))}
/>
)}
{objectRotation && (
<RotationInput
disabled={true}
onChange={() => { }}
value={parseFloat(objectRotation.y.toFixed(5))}
/>
)}
</section>
<div className="header">Render settings</div>
<section>
<InputToggle inputKey="visible" label="Visible" />
<InputToggle inputKey="frustumCull" label="Frustum cull" />
</section>
<section>
<div className="header">User Data</div>
{userData.map((data, i) => (
<div className="input-container" key={i}>
<InputWithDropDown
key={data.id}
label={data.label}
value={data.value}
editableLabel
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
/>
<div
className="remove-button"
onClick={() => handleRemoveUserData(data.id)}
>
<RemoveIcon />
</div>
</div>
))}
{/* Add new user data */}
<div className="optimize-button" onClick={handleAddUserData}>
+ Add
</div>
</section>
<div className="header">Animations</div>
<section className="animations-lists">
{assets.map((asset, i) => {
if (asset.modelUuid !== selectedFloorItem.uuid || !asset.animations)
return (
i === 0 && (
<div className="no-animation" key={i}>
Looks like there are no preset animations yet. Stay tuned for
future additions!
</div>
)
const handleAnimationClick = (animation: string) => {
if (selectedFloorAsset) {
setCurrentAnimation(
selectedFloorAsset.uuid,
animation,
true,
loopAnimation,
true
);
}
};
return asset.animations.map((animation, index) => (
<div key={index} className="animations-list-wrapper">
<div
onClick={() => handleAnimationClick(animation)}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}
className="animations-list"
style={{
background:
hoveredIndex === index
? "var(--background-color-button)"
: "var(--background-color)",
color:
hoveredIndex === index ? "var(--text-button-color)" : "",
}}
>
{animation.charAt(0).toUpperCase() +
animation.slice(1).toLowerCase()}
</div>
</div>
));
})}
</section>
</div>
);
if (!selectedFloorAsset) return null;
return (
<div className="asset-properties-container">
{/* Name */}
<div className="header">{selectedFloorAsset.userData.modelName}</div>
<section>
{objectPosition && (
<PositionInput
disabled={true}
onChange={() => { }}
value1={parseFloat(objectPosition.x.toFixed(5))}
value2={parseFloat(objectPosition.z.toFixed(5))}
/>
)}
{objectRotation && (
<RotationInput
disabled={true}
onChange={() => { }}
value={parseFloat(objectRotation.y.toFixed(5))}
/>
)}
</section>
<div className="header">Render settings</div>
<section>
<InputToggle inputKey="visible" label="Visible" />
<InputToggle inputKey="frustumCull" label="Frustum cull" />
</section>
<section>
<div className="header">User Data</div>
{userData.map((data, i) => (
<div className="input-container" key={i}>
<InputWithDropDown
key={data.id}
label={data.label}
value={data.value}
editableLabel
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
/>
<div
className="remove-button"
onClick={() => handleRemoveUserData(data.id)}
>
<RemoveIcon />
</div>
</div>
))}
{/* Add new user data */}
<div className="optimize-button" onClick={handleAddUserData}>
+ Add
</div>
</section>
<div className="header">Animations</div>
<section className="animations-lists">
{assets.map((asset, i) => {
if (asset.modelUuid !== selectedFloorAsset.uuid || !asset.animations)
return (
i === 0 && (
<div className="no-animation" key={i}>
Looks like there are no preset animations yet. Stay tuned for
future additions!
</div>
)
);
return asset.animations.map((animation, index) => (
<div key={index} className="animations-list-wrapper">
<div
onClick={() => handleAnimationClick(animation)}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}
className="animations-list"
style={{
background:
hoveredIndex === index
? "var(--background-color-button)"
: "var(--background-color)",
color:
hoveredIndex === index ? "var(--text-button-color)" : "",
}}
>
{animation.charAt(0).toUpperCase() +
animation.slice(1).toLowerCase()}
</div>
</div>
));
})}
</section>
</div>
);
};
export default AssetProperties;

View File

@@ -3,27 +3,13 @@ import InputRange from "../../../ui/inputs/InputRange";
import InputToggle from "../../../ui/inputs/InputToggle";
import { AIIcon } from "../../../icons/ExportCommonIcons";
import LabeledButton from "../../../ui/inputs/LabledButton";
import {
useAzimuth,
useElevation,
useLimitDistance,
useRenderDistance,
useResetCamera,
useRoofVisibility,
useSelectedWallItem,
useShadows,
useSocketStore,
useTileDistance,
useToggleView,
useWallVisibility,
} from "../../../../store/builder/store";
import { useAzimuth, useElevation, useLimitDistance, useRenderDistance, useResetCamera, useRoofVisibility, useShadows, useSocketStore, useTileDistance, useToggleView, useWallVisibility } from "../../../../store/builder/store";
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
const GlobalProperties: React.FC = () => {
const { toggleView, setToggleView } = useToggleView();
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
const { wallVisibility, setWallVisibility } = useWallVisibility();
const { shadows, setShadows } = useShadows();
@@ -90,16 +76,6 @@ const GlobalProperties: React.FC = () => {
setDistance(value);
setRenderDistance(value);
}
function updateGridDistance(value: number) {
setGridDistance(value);
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
// setPlaneValue({ height: value * 100, width: value * 100 });
}
function updatedGrid(value: number) {
// console.log(" (value * 100) / 4 : ", (value * 100) / 4);
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
setPlaneValue({ height: value * 100, width: value * 100 });
}
const updatedDist = async (value: number) => {
setRenderDistance(value);
@@ -145,7 +121,7 @@ const GlobalProperties: React.FC = () => {
setRoofVisibility(!roofVisibility); // Toggle roof visibility
};
// Function to toggle wall visibility
const changeWallVisibility = async () => {
//using REST
const data = await setEnvironment(
@@ -203,20 +179,10 @@ const GlobalProperties: React.FC = () => {
const toggleResetCamera = () => {
if (!toggleView) {
setResetCamera(true); // Trigger reset camera action
setResetCamera(true);
}
};
// function changeRenderDistance(e: any) {
// if (parseInt(e.target.value) < 20) {
// setRenderDistance(20);
// } else if (parseInt(e.target.value) > 75) {
// setRenderDistance(75);
// } else {
// setRenderDistance(parseInt(e.target.value));
// }
// }
return (
<div className="global-properties-container">
<section>
@@ -253,16 +219,10 @@ const GlobalProperties: React.FC = () => {
/>
<div className="split"></div>
{/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
<InputToggle
inputKey="4"
label="Limit Render Distance"
value={limitDistance}
// onClick={() => {
// setLimitDistance(!limitDistance);
// // setDistance(75);
// // setRenderDistance(75);
// }}
onClick={async () => {
await limitRenderDistance(); // Call the function here
}}
@@ -277,26 +237,6 @@ const GlobalProperties: React.FC = () => {
onPointerUp={updatedDist}
key={"6"}
/>
{/* <div className="split"></div>
<InputToggle
inputKey="6"
label="Display Grid"
value={limitGridDistance}
onClick={() => {
setLimitGridDistance(!limitGridDistance);
}}
/>
<InputRange
label="Tile Distance"
disabled={!limitGridDistance}
value={gridDistance}
key={"7"}
min={1}
max={5}
onChange={(value: number) => updateGridDistance(value)}
onPointerUp={updatedGrid}
/> */}
</section>
</div>
);

View File

@@ -1,17 +1,17 @@
import React, { useEffect, useRef, useState } from "react";
import {
AsileIcon,
CommentIcon,
CursorIcon,
DeleteIcon,
FloorIcon,
FreeMoveIcon,
MeasureToolIcon,
PenIcon,
PlayIcon,
SaveTemplateIcon,
WallIcon,
ZoneIcon,
AsileIcon,
CommentIcon,
CursorIcon,
DeleteIcon,
FloorIcon,
FreeMoveIcon,
MeasureToolIcon,
PenIcon,
PlayIcon,
SaveTemplateIcon,
WallIcon,
ZoneIcon,
} from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
@@ -20,420 +20,417 @@ import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useTemplateStore from "../../store/useTemplateStore";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import {
useActiveTool,
useAddAction,
useSelectedWallItem,
useSocketStore,
useToggleView,
useToolMode,
useActiveSubTool,
useShortcutStore,
useActiveTool,
useAddAction,
useSocketStore,
useToggleView,
useToolMode,
useActiveSubTool,
useShortcutStore,
} from "../../store/builder/store";
import { useToggleStore } from "../../store/useUIToggleStore";
import {
use3DWidget,
useFloatingWidget,
use3DWidget,
useFloatingWidget,
} from "../../store/visualization/useDroppedObjectsStore";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../modules/builder/version/versionContext";
import { MoveIcon, RotateIcon } from "../icons/ShortcutIcons";
import { useBuilderStore } from "../../store/builder/useBuilderStore";
// Utility component
const ToolButton = ({
toolKey,
toolId,
icon: Icon,
active,
onClick,
tooltip,
toolKey,
toolId,
icon: Icon,
active,
onClick,
tooltip,
}: any) => (
<button
key={toolKey} // used in rendering list
id={toolId}
className={`tool-button ${active ? "active" : ""}`}
onClick={onClick}
>
<div className="tooltip">{tooltip}</div>
<div className="tool" id={toolId}>
<Icon isActive={active} />
</div>
</button>
<button
key={toolKey} // used in rendering list
id={toolId}
className={`tool-button ${active ? "active" : ""}`}
onClick={onClick}
>
<div className="tooltip">{tooltip}</div>
<div className="tool" id={toolId}>
<Icon isActive={active} />
</div>
</button>
);
const Tools: React.FC = () => {
const { activeModule } = useModuleStore();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { showShortcuts } = useShortcutStore();
const { activeModule } = useModuleStore();
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
const { isPlaying, setIsPlaying } = usePlayButtonStore();
const { showShortcuts } = useShortcutStore();
const { activeTool, setActiveTool, setToolMode, setAddAction } = useStoreHooks();
const { setSelectedWallAsset } = useBuilderStore();
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
const { setToggleUI } = useToggleStore();
const { setToggleView, toggleView } = useToggleView();
const { activeTool, setActiveTool, setToolMode, setAddAction } =
useStoreHooks();
const { addTemplate, templates } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget();
const { widgets3D } = use3DWidget();
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
const { setSelectedWallItem } = useSelectedWallItem();
const { setToggleUI } = useToggleStore();
const { setToggleView, toggleView } = useToggleView();
const { visualizationSocket } = useSocketStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { addTemplate, templates } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget();
const { widgets3D } = use3DWidget();
const dropdownRef = useRef<HTMLButtonElement>(null);
const [openDrop, setOpenDrop] = useState(false);
const { visualizationSocket } = useSocketStore();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
// 1. Set UI toggles on initial render
useEffect(() => {
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const dropdownRef = useRef<HTMLButtonElement>(null);
const [openDrop, setOpenDrop] = useState(false);
// 2. Update tool based on subtool and module
useEffect(() => {
setActiveTool(activeSubTool);
setActiveSubTool(activeSubTool);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeModule]);
// 1. Set UI toggles on initial render
useEffect(() => {
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// 3. Update tools behavior based on selected tool and view mode
useEffect(() => {
resetTools();
updateToolBehavior(activeTool, toggleView);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTool, toggleView]);
// 2. Update tool based on subtool and module
useEffect(() => {
setActiveTool(activeSubTool);
setActiveSubTool(activeSubTool);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeModule]);
// 4. Dropdown auto-close
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(e.target as Node)
) {
setOpenDrop(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
// 3. Update tools behavior based on selected tool and view mode
useEffect(() => {
resetTools();
updateToolBehavior(activeTool, toggleView);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTool, toggleView]);
// 4. Dropdown auto-close
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(e.target as Node)
) {
setOpenDrop(false);
}
const resetTools = () => {
setToolMode(null);
setAddAction(null);
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
const resetTools = () => {
setToolMode(null);
setAddAction(null);
};
const updateToolBehavior = (tool: string, is2D: boolean) => {
switch (tool) {
case "cursor":
is2D ? setToolMode("move") : setToolMode("cursor");
break;
case "draw-wall":
is2D && setToolMode("Wall");
break;
case "draw-aisle":
is2D && setToolMode("Aisle");
break;
case "draw-zone":
is2D && setToolMode("Zone");
break;
case "draw-floor":
is2D && setToolMode("Floor");
break;
case "move":
if (!is2D) setToolMode("Move-Asset");
break;
case "rotate":
if (!is2D) setToolMode("Rotate-Asset");
break;
case "measure":
setToolMode("MeasurementScale");
break;
case "Add pillar":
if (!is2D) setAddAction("Pillar");
break;
case "delete":
is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
break;
}
};
const toggle2D3D = () => {
const toggleTo2D = toggleView;
setToggleView(!toggleTo2D);
setToggleThreeD(toggleTo2D);
setToggleUI(toggleTo2D, toggleTo2D);
if (toggleTo2D) {
setSelectedWallItem(null);
setAddAction(null);
}
setActiveTool("cursor");
setActiveSubTool("cursor");
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
};
const renderBuilderTools = () => (
<>
{!toggleThreeD && (
<div className="draw-tools">
<ToolButton
toolId="drawWall"
icon={WallIcon}
tooltip="draw wall (q)"
active={activeTool === "draw-wall"}
onClick={() => setActiveTool("draw-wall")}
/>
<ToolButton
toolId="drawZone"
icon={ZoneIcon}
tooltip="draw zone (e)"
active={activeTool === "draw-zone"}
onClick={() => setActiveTool("draw-zone")}
/>
<ToolButton
toolId="drawAisle"
icon={AsileIcon}
tooltip="draw aisle (r)"
active={activeTool === "draw-aisle"}
onClick={() => setActiveTool("draw-aisle")}
/>
<ToolButton
toolId="drawFloor"
icon={FloorIcon}
tooltip="draw floor (t)"
active={activeTool === "draw-floor"}
onClick={() => setActiveTool("draw-floor")}
/>
</div>
)}
<div className="draw-tools">
<ToolButton
toolId="measureScale"
icon={MeasureToolIcon}
tooltip="measure scale (m)"
active={activeTool === "measure"}
onClick={() => setActiveTool("measure")}
/>
</div>
</>
);
const renderSimulationTools = () => (
<div className="draw-tools">
<ToolButton
toolId="pen"
icon={PenIcon}
tooltip="pen"
active={activeTool === "pen"}
onClick={() => setActiveTool("pen")}
/>
</div>
);
const renderVisualizationTools = () => (
<div className="draw-tools">
<ToolButton
toolId="saveTemplate"
icon={SaveTemplateIcon}
tooltip="save template"
active={false}
onClick={() =>
handleSaveTemplate({
addTemplate,
floatingWidget,
widgets3D,
selectedZone,
templates,
visualizationSocket,
projectId,
versionId: selectedVersion?.versionId || "",
})
const updateToolBehavior = (tool: string, is2D: boolean) => {
switch (tool) {
case "cursor":
is2D ? setToolMode("move") : setToolMode("cursor");
break;
case "draw-wall":
is2D && setToolMode("Wall");
break;
case "draw-aisle":
is2D && setToolMode("Aisle");
break;
case "draw-zone":
is2D && setToolMode("Zone");
break;
case "draw-floor":
is2D && setToolMode("Floor");
break;
case "move":
if (!is2D) setToolMode("Move-Asset");
break;
case "rotate":
if (!is2D) setToolMode("Rotate-Asset");
break;
case "measure":
setToolMode("MeasurementScale");
break;
case "Add pillar":
if (!is2D) setAddAction("Pillar");
break;
case "delete":
is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
break;
}
/>
</div>
);
};
const renderModeSwitcher = () => (
<button
id="toggle-threed-button"
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""}`}
onClick={toggle2D3D}
>
<div className="tooltip">toggle view (tab)</div>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>2d</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>3d</div>
</button>
);
const toggle2D3D = () => {
const toggleTo2D = toggleView;
setToggleView(!toggleTo2D);
setToggleThreeD(toggleTo2D);
setToggleUI(toggleTo2D, toggleTo2D);
if (toggleTo2D) {
setSelectedWallAsset(null);
setAddAction(null);
}
setActiveTool("cursor");
setActiveSubTool("cursor");
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
};
const getIconByTool = (tool: string) => {
switch (tool) {
case "cursor":
return CursorIcon;
case "free-hand":
return FreeMoveIcon;
case "delete":
return DeleteIcon;
case "move":
return MoveIcon;
case "rotate":
return RotateIcon;
default:
return CursorIcon;
}
};
const getTooltipShortcut = (tool: string) => {
switch (tool) {
case "cursor":
return "v";
case "free-hand":
return "h";
case "delete":
return "x";
default:
return "";
}
};
const getIconComponent = (option: string) => {
switch (option) {
case "cursor":
return <CursorIcon isActive={false} />;
case "free-hand":
return <FreeMoveIcon isActive={false} />;
case "delete":
return <DeleteIcon isActive={false} />;
case "move":
return <MoveIcon />;
case "rotate":
return <RotateIcon />;
default:
return null;
}
};
return (
<div className={`tools-container ${showShortcuts ? "visible" : ""}`}>
<div className="activeDropicon">
{/* Tool Picker (cursor, delete, etc.) */}
{["cursor", "free-hand", "delete"].map(
(tool) =>
activeSubTool === tool && (
<ToolButton
key={tool}
toolId={tool}
icon={getIconByTool(tool)}
tooltip={`${tool} (${getTooltipShortcut(tool)})`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
)
)}
{/* Dropdown Menu */}
{activeModule !== "visualization" && (
<button
id="drop-down-button"
title="drop-down"
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => setOpenDrop(!openDrop)}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
{["cursor", "free-hand", "delete"].map((option) => (
<button
key={option}
id={`${option}-tool`}
className="option-list"
onClick={() => {
setActiveTool(option);
setActiveSubTool(option);
setOpenDrop(false);
}}
>
<div className="active-option">
{activeSubTool === option && <TickIcon />}
</div>
{getIconComponent(option)}
<div className="option">{option}</div>
</button>
))}
</div>
const renderBuilderTools = () => (
<>
{!toggleThreeD && (
<div className="draw-tools">
<ToolButton
toolId="drawWall"
icon={WallIcon}
tooltip="draw wall (q)"
active={activeTool === "draw-wall"}
onClick={() => setActiveTool("draw-wall")}
/>
<ToolButton
toolId="drawZone"
icon={ZoneIcon}
tooltip="draw zone (e)"
active={activeTool === "draw-zone"}
onClick={() => setActiveTool("draw-zone")}
/>
<ToolButton
toolId="drawAisle"
icon={AsileIcon}
tooltip="draw aisle (r)"
active={activeTool === "draw-aisle"}
onClick={() => setActiveTool("draw-aisle")}
/>
<ToolButton
toolId="drawFloor"
icon={FloorIcon}
tooltip="draw floor (t)"
active={activeTool === "draw-floor"}
onClick={() => setActiveTool("draw-floor")}
/>
</div>
)}
</button>
)}
</div>
{toggleThreeD && activeModule !== "visualization" && (
<>
<div className="split"></div>
<div className="transform-tools">
{["move", "rotate"].map((tool) => (
<ToolButton
key={tool}
toolId={tool}
icon={getIconByTool(tool)}
tooltip={`${tool}`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
))}
</div>
<div className="draw-tools">
<ToolButton
toolId="measureScale"
icon={MeasureToolIcon}
tooltip="measure scale (m)"
active={activeTool === "measure"}
onClick={() => setActiveTool("measure")}
/>
</div>
</>
)}
);
<div className="split"></div>
{activeModule === "builder" && renderBuilderTools()}
{activeModule === "simulation" && renderSimulationTools()}
{activeModule === "visualization" && renderVisualizationTools()}
const renderSimulationTools = () => (
<div className="draw-tools">
<ToolButton
toolId="pen"
icon={PenIcon}
tooltip="pen"
active={activeTool === "pen"}
onClick={() => setActiveTool("pen")}
/>
</div>
);
<div className="split"></div>
<div className="general-options">
<ToolButton
toolId="comment"
icon={CommentIcon}
tooltip="comment"
active={activeTool === "comment"}
onClick={() => setActiveTool("comment")}
/>
{toggleThreeD && (
<ToolButton
toolId="play"
icon={PlayIcon}
tooltip="play (ctrl + p)"
active={activeTool === "play"}
onClick={() => setIsPlaying(!isPlaying)}
/>
)}
</div>
const renderVisualizationTools = () => (
<div className="draw-tools">
<ToolButton
toolId="saveTemplate"
icon={SaveTemplateIcon}
tooltip="save template"
active={false}
onClick={() =>
handleSaveTemplate({
addTemplate,
floatingWidget,
widgets3D,
selectedZone,
templates,
visualizationSocket,
projectId,
versionId: selectedVersion?.versionId || "",
})
}
/>
</div>
);
{activeModule === "builder" && (
<>
<div className="split"></div>
{renderModeSwitcher()}
</>
)}
</div>
);
const renderModeSwitcher = () => (
<button
id="toggle-threed-button"
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""}`}
onClick={toggle2D3D}
>
<div className="tooltip">toggle view (tab)</div>
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>2d</div>
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>3d</div>
</button>
);
const getIconByTool = (tool: string) => {
switch (tool) {
case "cursor":
return CursorIcon;
case "free-hand":
return FreeMoveIcon;
case "delete":
return DeleteIcon;
case "move":
return MoveIcon;
case "rotate":
return RotateIcon;
default:
return CursorIcon;
}
};
const getTooltipShortcut = (tool: string) => {
switch (tool) {
case "cursor":
return "v";
case "free-hand":
return "h";
case "delete":
return "x";
default:
return "";
}
};
const getIconComponent = (option: string) => {
switch (option) {
case "cursor":
return <CursorIcon isActive={false} />;
case "free-hand":
return <FreeMoveIcon isActive={false} />;
case "delete":
return <DeleteIcon isActive={false} />;
case "move":
return <MoveIcon />;
case "rotate":
return <RotateIcon />;
default:
return null;
}
};
return (
<div className={`tools-container ${showShortcuts ? "visible" : ""}`}>
<div className="activeDropicon">
{/* Tool Picker (cursor, delete, etc.) */}
{["cursor", "free-hand", "delete"].map(
(tool) =>
activeSubTool === tool && (
<ToolButton
key={tool}
toolId={tool}
icon={getIconByTool(tool)}
tooltip={`${tool} (${getTooltipShortcut(tool)})`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
)
)}
{/* Dropdown Menu */}
{activeModule !== "visualization" && (
<button
id="drop-down-button"
title="drop-down"
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => setOpenDrop(!openDrop)}
>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
{["cursor", "free-hand", "delete"].map((option) => (
<button
key={option}
id={`${option}-tool`}
className="option-list"
onClick={() => {
setActiveTool(option);
setActiveSubTool(option);
setOpenDrop(false);
}}
>
<div className="active-option">
{activeSubTool === option && <TickIcon />}
</div>
{getIconComponent(option)}
<div className="option">{option}</div>
</button>
))}
</div>
)}
</button>
)}
</div>
{toggleThreeD && activeModule !== "visualization" && (
<>
<div className="split"></div>
<div className="transform-tools">
{["move", "rotate"].map((tool) => (
<ToolButton
key={tool}
toolId={tool}
icon={getIconByTool(tool)}
tooltip={`${tool}`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
))}
</div>
</>
)}
<div className="split"></div>
{activeModule === "builder" && renderBuilderTools()}
{activeModule === "simulation" && renderSimulationTools()}
{activeModule === "visualization" && renderVisualizationTools()}
<div className="split"></div>
<div className="general-options">
<ToolButton
toolId="comment"
icon={CommentIcon}
tooltip="comment"
active={activeTool === "comment"}
onClick={() => setActiveTool("comment")}
/>
{toggleThreeD && (
<ToolButton
toolId="play"
icon={PlayIcon}
tooltip="play (ctrl + p)"
active={activeTool === "play"}
onClick={() => setIsPlaying(!isPlaying)}
/>
)}
</div>
{activeModule === "builder" && (
<>
<div className="split"></div>
{renderModeSwitcher()}
</>
)}
</div>
);
};
// Extracted common store logic
const useStoreHooks = () => {
return {
...useActiveTool(),
...useToolMode(),
...useAddAction(),
};
return {
...useActiveTool(),
...useToolMode(),
...useAddAction(),
};
};
export default Tools;