updated
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Cache } from "three";
|
||||
import { BrowserRouter as Router, Routes, Route, useParams } from "react-router-dom";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import Dashboard from "./pages/Dashboard";
|
||||
import Project from "./pages/Project";
|
||||
import UserAuth from "./pages/UserAuth";
|
||||
@@ -14,7 +14,6 @@ const App: React.FC = () => {
|
||||
Cache.enabled = true;
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<LoggerProvider>
|
||||
<Router>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import img from "../../assets/image/image.png";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getUserData } from "./functions/getUserData";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useLoadingProgress, useProjectName, useSocketStore } from "../../store/builder/store";
|
||||
import { viewProject } from "../../services/dashboard/viewProject";
|
||||
import OuterClick from "../../utils/outerClick";
|
||||
@@ -60,12 +60,6 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
|
||||
const navigateToProject = async (e: any) => {
|
||||
if (active && active == "trash") return;
|
||||
try {
|
||||
const viewedProject = await viewProject(organization, projectId, userId);
|
||||
console.log("Viewed project:", viewedProject);
|
||||
} catch (error) {
|
||||
console.error("Error opening project:", error);
|
||||
}
|
||||
setLoadingProgress(1)
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
@@ -75,9 +69,9 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
switch (option) {
|
||||
case "delete":
|
||||
if (handleDeleteProject) {
|
||||
await handleDeleteProject(projectId);
|
||||
handleDeleteProject(projectId);
|
||||
} else if (handleTrashDeleteProject) {
|
||||
await handleTrashDeleteProject(projectId);
|
||||
handleTrashDeleteProject(projectId);
|
||||
}
|
||||
break;
|
||||
case "restore":
|
||||
@@ -133,7 +127,7 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
if (!projectId) return;
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
console.log("projects: ", projects);
|
||||
// console.log("projects: ", projects);
|
||||
let projectUuid = projects.Projects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
);
|
||||
@@ -264,7 +258,6 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
console.log("option", option);
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||
import DashboardCard from "./DashboardCard";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
import MarketPlaceBanner from "./MarketPlaceBanner";
|
||||
import { getUserData } from "./functions/getUserData";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useSocketStore } from "../../store/builder/store";
|
||||
import { recentlyViewed } from "../../services/dashboard/recentlyViewed";
|
||||
import { searchProject } from "../../services/dashboard/searchProjects";
|
||||
@@ -34,8 +34,7 @@ const DashboardHome: React.FC = () => {
|
||||
const fetchRecentProjects = async () => {
|
||||
try {
|
||||
const projects = await recentlyViewed(organization, userId);
|
||||
console.log("RecentlyViewed: ", projects);
|
||||
|
||||
|
||||
if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) {
|
||||
setRecentProjects(projects);
|
||||
}
|
||||
@@ -59,7 +58,6 @@ const DashboardHome: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleDeleteProject = async (projectId: any) => {
|
||||
console.log("projectId:delete ", projectId);
|
||||
try {
|
||||
//API for delete project
|
||||
// const deletedProject = await deleteProject(
|
||||
@@ -115,6 +113,7 @@ const DashboardHome: React.FC = () => {
|
||||
|
||||
const renderProjects = () => {
|
||||
const projectList = recentProjects[Object.keys(recentProjects)[0]];
|
||||
console.log('projectList: ', projectList);
|
||||
|
||||
if (!projectList?.length) {
|
||||
return <div className="empty-state">No recent projects found</div>;
|
||||
@@ -150,7 +149,7 @@ const DashboardHome: React.FC = () => {
|
||||
handleRecentProjectSearch={handleRecentProjectSearch}
|
||||
/>
|
||||
<MarketPlaceBanner />
|
||||
<div className="container">
|
||||
<div className="dashboard-container">
|
||||
<h2 className="section-header">Recents</h2>
|
||||
<div className="cards-container">{renderProjects()}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
import DashboardCard from "./DashboardCard";
|
||||
import { getUserData } from "./functions/getUserData";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useSocketStore } from "../../store/builder/store";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { searchProject } from "../../services/dashboard/searchProjects";
|
||||
@@ -65,7 +65,7 @@ const DashboardProjects: React.FC = () => {
|
||||
// console.log('deletedProject: ', deletedProject);
|
||||
const deleteProjects = {
|
||||
projectId,
|
||||
organization: organization,
|
||||
organization,
|
||||
userId,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import DashboardCard from "./DashboardCard";
|
||||
import DashboardNavBar from "./DashboardNavBar";
|
||||
import { getUserData } from "./functions/getUserData";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { trashSearchProject } from "../../services/dashboard/trashSearchProject";
|
||||
import { restoreTrash } from "../../services/dashboard/restoreTrash";
|
||||
import { getTrash } from "../../services/dashboard/getTrash";
|
||||
@@ -22,9 +22,7 @@ interface DiscardedProjects {
|
||||
}
|
||||
|
||||
const DashboardTrash: React.FC = () => {
|
||||
const [discardedProjects, setDiscardedProjects] = useState<DiscardedProjects>(
|
||||
{}
|
||||
);
|
||||
const [discardedProjects, setDiscardedProjects] = useState<DiscardedProjects>({});
|
||||
const [isSearchActive, setIsSearchActive] = useState(false);
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectSocket } = useSocketStore();
|
||||
@@ -60,7 +58,6 @@ const DashboardTrash: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleRestoreProject = async (projectId: any) => {
|
||||
console.log("projectId: ", projectId);
|
||||
try {
|
||||
const restoreProject = await restoreTrash(organization, projectId);
|
||||
// console.log('restoreProject: ', restoreProject);
|
||||
@@ -86,6 +83,7 @@ const DashboardTrash: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleTrashDeleteProject = async (projectId: any) => {
|
||||
console.log('projectId: ', projectId);
|
||||
try {
|
||||
// const deletedProject = await deleteTrash(
|
||||
// organization, projectId
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import darkThemeImage from "../../assets/image/darkThemeProject.png";
|
||||
import lightThemeImage from "../../assets/image/lightThemeProject.png";
|
||||
import { SettingsIcon, TrashIcon } from "../icons/ExportCommonIcons";
|
||||
import { getUserData } from "./functions/getUserData";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { useLoadingProgress, useSocketStore } from "../../store/builder/store";
|
||||
import { createProject } from "../../services/dashboard/createProject";
|
||||
|
||||
@@ -42,7 +42,7 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
const projectId = generateProjectId();
|
||||
useSocketStore.getState().initializeSocket(email, organization, token);
|
||||
|
||||
|
||||
|
||||
//API for creating new Project
|
||||
// const project = await createProject(
|
||||
// projectId,
|
||||
@@ -57,11 +57,11 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
organization: organization,
|
||||
projectUuid: projectId,
|
||||
};
|
||||
console.log("projectSocket: ", projectSocket);
|
||||
// console.log("projectSocket: ", projectSocket);
|
||||
if (projectSocket) {
|
||||
// console.log('addProject: ', addProject);
|
||||
const handleResponse = (data: any) => {
|
||||
console.log('Project add response:', data);
|
||||
// console.log('Project add response:', data);
|
||||
if (data.message === "Project created successfully") {
|
||||
setLoadingProgress(1)
|
||||
navigate(`/${data.data.projectId}`);
|
||||
@@ -70,7 +70,7 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
};
|
||||
projectSocket.on("v1-project:response:add", handleResponse);
|
||||
|
||||
console.log('addProject: ', addProject);
|
||||
// console.log('addProject: ', addProject);
|
||||
projectSocket.emit("v1:project:add", addProject);
|
||||
} else {
|
||||
console.error("Socket is not connected.");
|
||||
@@ -163,7 +163,10 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
<SettingsIcon />
|
||||
Settings
|
||||
</div>
|
||||
<div className="option-list" style={{ cursor: "pointer" }}>
|
||||
<div className="option-list" style={{ cursor: "pointer" }} onClick={() => {
|
||||
localStorage.clear();
|
||||
navigate("/");
|
||||
}}>
|
||||
<LogoutIcon />
|
||||
Log out
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSocketStore } from '../../../store/builder/store';
|
||||
import { getUserData } from '../functions/getUserData';
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import { getAllProjects } from '../../../services/dashboard/getAllProjects';
|
||||
import { recentlyViewed } from '../../../services/dashboard/recentlyViewed';
|
||||
|
||||
@@ -56,7 +56,7 @@ const ProjectSocketRes = ({
|
||||
if (data?.message === "Project Duplicated successfully") {
|
||||
if (setWorkspaceProjects) {
|
||||
const allProjects = await getAllProjects(userId, organization);
|
||||
console.log('allProjects: ', allProjects);
|
||||
// console.log('allProjects: ', allProjects);
|
||||
setWorkspaceProjects(allProjects);
|
||||
} else if (setRecentProjects) {
|
||||
const recentProjects = await recentlyViewed(organization, userId);
|
||||
|
||||
@@ -8,15 +8,22 @@ import {
|
||||
CurserRightIcon,
|
||||
} from "../icons/LogIcons";
|
||||
import ShortcutHelper from "./shortcutHelper";
|
||||
import { useShortcutStore } from "../../store/builder/store";
|
||||
import useVersionHistoryVisibleStore, { useShortcutStore } from "../../store/builder/store";
|
||||
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
||||
import useModuleStore, { useSubModuleStore } from "../../store/useModuleStore";
|
||||
import { useVersionContext } from "../../modules/builder/version/versionContext";
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
const { logs, setIsLogListVisible } = useLogger();
|
||||
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
|
||||
|
||||
const { setActiveModule } = useModuleStore();
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
return (
|
||||
<div className="footer-container">
|
||||
@@ -61,8 +68,12 @@ const Footer: React.FC = () => {
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div className="version">
|
||||
V 0.01
|
||||
<div className="version" onClick={() => {
|
||||
setVersionHistoryVisible(true);
|
||||
setSubModule("properties");
|
||||
setActiveModule('builder');
|
||||
}}>
|
||||
{(selectedVersion?.version) ?? 'v 0.0.0'}
|
||||
<div className="icon">
|
||||
<HelpIcon />
|
||||
</div>
|
||||
@@ -72,11 +83,10 @@ const Footer: React.FC = () => {
|
||||
|
||||
{!isPlaying && (
|
||||
<div
|
||||
className={`shortcut-helper-overlay ${
|
||||
showShortcuts ? "visible" : ""
|
||||
}`}
|
||||
className={`shortcut-helper-overlay ${showShortcuts ? "visible" : ""
|
||||
}`}
|
||||
>
|
||||
<ShortcutHelper setShowShortcuts={setShowShortcuts}/>
|
||||
<ShortcutHelper setShowShortcuts={setShowShortcuts} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useProductContext } from '../../../modules/simulation/products/productContext'
|
||||
import RegularDropDown from '../../ui/inputs/RegularDropDown';
|
||||
import { useProductStore } from '../../../store/simulation/useProductStore';
|
||||
import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
import CompareLayOut from '../../ui/compareVersion/CompareLayOut';
|
||||
@@ -8,10 +7,14 @@ import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
|
||||
import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore';
|
||||
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useVersionHistoryStore } from '../../../store/builder/useVersionHistoryStore';
|
||||
import { useVersionContext } from '../../../modules/builder/version/versionContext';
|
||||
import { useSceneContext } from '../../../modules/scene/sceneContext';
|
||||
|
||||
function ComparisonScene() {
|
||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||
const { products } = useProductStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { products } = productStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
@@ -21,13 +24,30 @@ function ComparisonScene() {
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||
const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false);
|
||||
const { versionHistory } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
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) {
|
||||
setComparisonProduct(product.productUuid, product.productName);
|
||||
}
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// if (versionHistory.length > 0) {
|
||||
// setSelectedVersion(versionHistory[0])
|
||||
// }
|
||||
// }, [versionHistory])
|
||||
|
||||
// useEffect(() => {
|
||||
// setCompareProductsData([
|
||||
// {
|
||||
@@ -57,7 +77,7 @@ function ComparisonScene() {
|
||||
// }
|
||||
// }
|
||||
// ])
|
||||
// }, []); // ✅ Runs only once on mount
|
||||
// }, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -79,12 +99,19 @@ function ComparisonScene() {
|
||||
<>
|
||||
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
||||
<>
|
||||
{comparisonProduct && !isPlaying &&
|
||||
{selectedVersion && !isPlaying &&
|
||||
<div className="initial-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={handleSelectLayout}
|
||||
onSelect={handleSelectProduct}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { useEffect } from 'react';
|
||||
import { ProductProvider } from '../../../modules/simulation/products/productContext'
|
||||
import ComparisonScene from './ComparisonScene';
|
||||
import { useSceneContext } from '../../../modules/scene/sceneContext';
|
||||
|
||||
function ComparisonSceneProvider() {
|
||||
const { assetStore } = useSceneContext();
|
||||
const { clearAssets } = assetStore();
|
||||
|
||||
useEffect(() => {
|
||||
clearAssets();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ProductProvider>
|
||||
<ComparisonScene />
|
||||
|
||||
@@ -30,15 +30,17 @@ import {
|
||||
useMainProduct,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
||||
import { useProductStore } from "../../../store/simulation/useProductStore";
|
||||
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
||||
import RenameTooltip from "../../ui/features/RenameTooltip";
|
||||
import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||
import { useAssetsStore } from "../../../store/builder/useAssetStore";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
|
||||
import Footer from "../../footer/Footer";
|
||||
|
||||
function MainScene() {
|
||||
const { products } = useProductStore();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
@@ -54,9 +56,14 @@ function MainScene() {
|
||||
const { setFloatingWidget } = useFloatingWidget();
|
||||
const { clearComparisonProduct } = useComparisonProduct();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { setName } = useAssetsStore();
|
||||
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();
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== 'simulation') {
|
||||
@@ -65,22 +72,33 @@ function MainScene() {
|
||||
}
|
||||
}, [activeModule])
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
useEffect(() => {
|
||||
if (versionHistory.length > 0) {
|
||||
setSelectedVersion(versionHistory[0])
|
||||
}
|
||||
}, [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
|
||||
const email = localStorage.getItem("email") ?? "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let response = await setFloorItemApi(
|
||||
organization,
|
||||
selectedFloorItem.userData.modelUuid,
|
||||
newName,
|
||||
let response = await setAssetsApi({
|
||||
modelUuid: selectedFloorItem.userData.modelUuid,
|
||||
modelName: newName,
|
||||
projectId
|
||||
);
|
||||
});
|
||||
selectedFloorItem.userData = {
|
||||
...selectedFloorItem.userData,
|
||||
modelName: newName
|
||||
@@ -98,7 +116,7 @@ function MainScene() {
|
||||
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||
{!isPlaying && (
|
||||
<>
|
||||
{toggleThreeD && <ModuleToggle />}
|
||||
{toggleThreeD && !isVersionSaved && <ModuleToggle />}
|
||||
<SideBarLeft />
|
||||
<SideBarRight />
|
||||
</>
|
||||
@@ -137,6 +155,8 @@ function MainScene() {
|
||||
selectedZone,
|
||||
setFloatingWidget,
|
||||
event,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
@@ -144,16 +164,28 @@ function MainScene() {
|
||||
<Scene layout="Main Layout" />
|
||||
</div>
|
||||
|
||||
{selectedProduct && isVersionSaved && !isPlaying && activeModule === "simulation" && (
|
||||
{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={handleSelectLayout}
|
||||
onSelect={handleSelectProduct}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
||||
|
||||
<VersionSaved />
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { useEffect } from 'react'
|
||||
import { ProductProvider } from '../../../modules/simulation/products/productContext'
|
||||
import MainScene from './MainScene'
|
||||
import { useSceneContext } from '../../../modules/scene/sceneContext';
|
||||
|
||||
function MainSceneProvider() {
|
||||
const { assetStore } = useSceneContext();
|
||||
const { clearAssets } = assetStore();
|
||||
|
||||
useEffect(() => {
|
||||
clearAssets();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ProductProvider>
|
||||
<MainScene />
|
||||
|
||||
@@ -14,7 +14,7 @@ const Header: React.FC = () => {
|
||||
return (
|
||||
<div className="header-container">
|
||||
<div className="header-content">
|
||||
<button className="logo-container" onClick={()=>navigate("/Dashboard")}>
|
||||
<button className="logo-container" onClick={() => navigate("/Dashboard")} title="Back to Dashboard">
|
||||
<LogoIcon />
|
||||
</button>
|
||||
<div className="header-title">
|
||||
|
||||
@@ -7,7 +7,7 @@ const Outline: React.FC = () => {
|
||||
|
||||
const handleSearchChange = (value: string) => {
|
||||
setSearchValue(value);
|
||||
console.log(value); // Log the search value if needed
|
||||
// console.log(value); // Log the search value if needed
|
||||
};
|
||||
|
||||
const dropdownItems = [
|
||||
|
||||
@@ -30,7 +30,7 @@ const SideBarLeft: React.FC = () => {
|
||||
|
||||
const handleSearchChange = (value: string) => {
|
||||
// Log the search value for now
|
||||
console.log(value);
|
||||
// console.log(value);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -8,10 +8,11 @@ import { useSelectedUserStore } from "../../../store/collaboration/useCollabStor
|
||||
import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||
import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const { activeUsers } = useActiveUsers();
|
||||
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
||||
const { userName } = getUserData();
|
||||
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
@@ -113,7 +114,7 @@ const Header: React.FC = () => {
|
||||
))}
|
||||
</div>
|
||||
<div className="user-profile-container">
|
||||
<div className="user-profile">{userName[0]}</div>
|
||||
<div className="user-profile">{userName?.charAt(0).toUpperCase()}</div>
|
||||
<div className="user-organization">
|
||||
<img src={orgImg} alt="" />
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||
import Visualization from "./visualization/Visualization";
|
||||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
import useVersionHistoryStore, {
|
||||
import useVersionHistoryVisibleStore, {
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
useToolMode,
|
||||
@@ -38,7 +38,7 @@ const SideBarRight: React.FC = () => {
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
|
||||
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
|
||||
// Reset activeList whenever activeModule changes
|
||||
@@ -81,7 +81,7 @@ const SideBarRight: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("properties");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">properties</div>
|
||||
@@ -96,7 +96,7 @@ const SideBarRight: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("simulations");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">simulations</div>
|
||||
@@ -108,7 +108,7 @@ const SideBarRight: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("mechanics");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">mechanics</div>
|
||||
@@ -120,7 +120,7 @@ const SideBarRight: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("analysis");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">analysis</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ const Vector3Input: React.FC<PositionInputProps> = ({
|
||||
if (!value) return;
|
||||
const updatedValue = [...value] as [number, number, number];
|
||||
updatedValue[index] = parseFloat(newValue) || 0;
|
||||
console.log('updatedValue: ', updatedValue);
|
||||
// console.log('updatedValue: ', updatedValue);
|
||||
onChange(updatedValue);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
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();
|
||||
@@ -38,14 +39,13 @@ const GlobalProperties: React.FC = () => {
|
||||
const [limitGridDistance, setLimitGridDistance] = useState(false);
|
||||
const [gridDistance, setGridDistance] = useState<number>(3);
|
||||
const { projectId } = useParams();
|
||||
const { email, userId, organization } = getUserData();
|
||||
|
||||
const optimizeScene = async (value: any) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||
|
||||
setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
roofVisibility,
|
||||
shadows,
|
||||
@@ -58,13 +58,11 @@ const GlobalProperties: React.FC = () => {
|
||||
};
|
||||
|
||||
const limitRenderDistance = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||
|
||||
if (limitDistance) {
|
||||
setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
roofVisibility,
|
||||
shadows,
|
||||
@@ -76,7 +74,7 @@ const GlobalProperties: React.FC = () => {
|
||||
} else {
|
||||
setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
roofVisibility,
|
||||
shadows,
|
||||
@@ -104,13 +102,11 @@ const GlobalProperties: React.FC = () => {
|
||||
}
|
||||
|
||||
const updatedDist = async (value: number) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg";
|
||||
setRenderDistance(value);
|
||||
// setDistance(value);
|
||||
const data = await setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
roofVisibility,
|
||||
shadows,
|
||||
@@ -122,13 +118,11 @@ const GlobalProperties: React.FC = () => {
|
||||
|
||||
// Function to toggle roof visibility
|
||||
const changeRoofVisibility = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
//using REST
|
||||
const data = await setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
!roofVisibility,
|
||||
shadows,
|
||||
@@ -153,12 +147,10 @@ const GlobalProperties: React.FC = () => {
|
||||
};
|
||||
// Function to toggle wall visibility
|
||||
const changeWallVisibility = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
//using REST
|
||||
const data = await setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
!wallVisibility,
|
||||
roofVisibility,
|
||||
shadows,
|
||||
@@ -182,12 +174,10 @@ const GlobalProperties: React.FC = () => {
|
||||
};
|
||||
|
||||
const shadowVisibility = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
//using REST
|
||||
const data = await setEnvironment(
|
||||
organization,
|
||||
localStorage.getItem("userId")!,
|
||||
userId,
|
||||
wallVisibility,
|
||||
roofVisibility,
|
||||
!shadows,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "../../../../store/builder/store";
|
||||
import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
const ZoneProperties: React.FC = () => {
|
||||
const { Edit, setEdit } = useEditPosition();
|
||||
@@ -17,7 +18,8 @@ const ZoneProperties: React.FC = () => {
|
||||
const { zonePosition, setZonePosition } = usezonePosition();
|
||||
const { zoneTarget, setZoneTarget } = usezoneTarget();
|
||||
const { zones, setZones } = useZones();
|
||||
const { projectId } = useParams()
|
||||
const { projectId } = useParams();
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
setZonePosition(selectedZone.zoneViewPortPosition);
|
||||
@@ -26,8 +28,6 @@ const ZoneProperties: React.FC = () => {
|
||||
|
||||
async function handleSetView() {
|
||||
try {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
let zonesdata = {
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
@@ -36,7 +36,7 @@ const ZoneProperties: React.FC = () => {
|
||||
};
|
||||
|
||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId);
|
||||
console.log('response: ', response);
|
||||
// console.log('response: ', response);
|
||||
if (response.message === "zone updated") {
|
||||
setEdit(false);
|
||||
} else {
|
||||
@@ -52,8 +52,6 @@ const ZoneProperties: React.FC = () => {
|
||||
}
|
||||
|
||||
async function handleZoneNameChange(newName: string) {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const zonesdata = {
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
zoneName: newName,
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
} from "../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import ConveyorMechanics from "./mechanics/conveyorMechanics";
|
||||
import VehicleMechanics from "./mechanics/vehicleMechanics";
|
||||
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
||||
@@ -11,21 +10,22 @@ import MachineMechanics from "./mechanics/machineMechanics";
|
||||
import StorageMechanics from "./mechanics/storageMechanics";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
|
||||
import { useProductContext } from "../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../modules/scene/sceneContext";
|
||||
|
||||
const EventProperties: React.FC = () => {
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getEventByModelUuid } = useProductStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { eventStore, productStore } = useSceneContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
|
||||
null
|
||||
);
|
||||
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(null);
|
||||
const [assetType, setAssetType] = useState<string | null>(null);
|
||||
const { products, addEvent } = useProductStore();
|
||||
const { products, addEvent, getEventByModelUuid } = productStore();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -102,14 +102,15 @@ const EventProperties: React.FC = () => {
|
||||
onClick={() => {
|
||||
if (selectedEventData) {
|
||||
handleAddEventToProduct({
|
||||
event: useEventsStore
|
||||
event: eventStore
|
||||
.getState()
|
||||
.getEventByModelUuid(
|
||||
selectedEventData?.data.modelUuid
|
||||
),
|
||||
addEvent,
|
||||
selectedProduct,
|
||||
projectId: projectId || ''
|
||||
projectId: projectId || '',
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -13,23 +13,26 @@ type Material = {
|
||||
textureName: string;
|
||||
};
|
||||
|
||||
// Initial and default material
|
||||
const initialMaterial: Material = {
|
||||
texture: wallTexture1,
|
||||
textureName: "Grunge Concrete Wall",
|
||||
};
|
||||
|
||||
// Default and initial materials
|
||||
const defaultMaterial: Material = {
|
||||
texture: defaultTexture,
|
||||
textureName: "Default Material",
|
||||
};
|
||||
|
||||
const initialMaterial: Material = {
|
||||
texture: wallTexture1,
|
||||
textureName: "Grunge Concrete Wall",
|
||||
};
|
||||
|
||||
const WallProperties = () => {
|
||||
const { wallHeight, wallThickness, setWallHeight, setWallThickness } = useBuilderStore();
|
||||
|
||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||
|
||||
const [materials, setMaterials] = useState<Material[]>([initialMaterial]);
|
||||
const [materials, setMaterials] = useState<Material[]>([
|
||||
defaultMaterial,
|
||||
initialMaterial,
|
||||
]);
|
||||
|
||||
const [selectedMaterials, setSelectedMaterials] = useState<{
|
||||
side1: Material | null;
|
||||
@@ -39,11 +42,11 @@ const WallProperties = () => {
|
||||
side2: null,
|
||||
});
|
||||
|
||||
// Select initial material for both sides on mount
|
||||
// Set default material initially for both sides
|
||||
useEffect(() => {
|
||||
setSelectedMaterials({
|
||||
side1: initialMaterial,
|
||||
side2: initialMaterial,
|
||||
side1: defaultMaterial,
|
||||
side2: defaultMaterial,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -71,21 +74,16 @@ const WallProperties = () => {
|
||||
};
|
||||
|
||||
const handleRemoveMaterial = (index: number) => {
|
||||
const updatedMaterials = materials.filter((_, i) => i !== index);
|
||||
const removedTexture = materials[index].texture;
|
||||
|
||||
// Ensure there's always at least one material
|
||||
const newMaterials =
|
||||
updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
|
||||
const updatedMaterials = materials.filter((_, i) => i !== index);
|
||||
const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
|
||||
setMaterials(newMaterials);
|
||||
|
||||
// Deselect the material if it's the one removed
|
||||
setSelectedMaterials((prev) => {
|
||||
const updated = { ...prev };
|
||||
["side1", "side2"].forEach((side) => {
|
||||
if (
|
||||
updated[side as "side1" | "side2"]?.texture ===
|
||||
materials[index].texture
|
||||
) {
|
||||
if (updated[side as "side1" | "side2"]?.texture === removedTexture) {
|
||||
updated[side as "side1" | "side2"] = defaultMaterial;
|
||||
}
|
||||
});
|
||||
@@ -119,42 +117,43 @@ const WallProperties = () => {
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
<div
|
||||
className={`side-wrapper ${activeSide === "side1" ? "active" : ""
|
||||
}`}
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side1" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side1")}
|
||||
>
|
||||
<div className="label">Side 1</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side1 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side1.texture}
|
||||
alt={selectedMaterials.side1.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div
|
||||
className={`side-wrapper ${activeSide === "side2" ? "active" : ""
|
||||
}`}
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side2" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side2")}
|
||||
>
|
||||
<div className="label">Side 2</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side2 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side2.texture}
|
||||
alt={selectedMaterials.side2.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
{selectedMaterials[activeSide] && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSide]!.texture}
|
||||
alt={selectedMaterials[activeSide]!.textureName}
|
||||
/>
|
||||
@@ -167,29 +166,37 @@ const WallProperties = () => {
|
||||
<div className="no-materials">No materials added yet.</div>
|
||||
) : (
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => (
|
||||
<div
|
||||
className="material-wrapper"
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img src={material.texture} alt={material.textureName} />
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
<div
|
||||
className="delete-material"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveMaterial(index);
|
||||
}}
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSide]?.texture === material.texture;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
<button
|
||||
className="delete-material"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveMaterial(index);
|
||||
}}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</button>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,10 +9,11 @@ import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||
import {
|
||||
useSelectedAction,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
interface ActionsListProps {
|
||||
selectedPointData: any;
|
||||
@@ -30,10 +31,14 @@ const ActionsList: React.FC<ActionsListProps> = ({
|
||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// store
|
||||
const { renameAction } = useProductStore();
|
||||
|
||||
const { productStore } = useSceneContext();
|
||||
const { renameAction } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { selectedAction, setSelectedAction } = useSelectedAction();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const handleRenameAction = (newName: string) => {
|
||||
@@ -50,6 +55,7 @@ const ActionsList: React.FC<ActionsListProps> = ({
|
||||
productUuid: selectedProduct.productUuid,
|
||||
projectId,
|
||||
eventDatas: event,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,21 +9,25 @@ import SpawnAction from "../actions/SpawnAction";
|
||||
import DefaultAction from "../actions/DefaultAction";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
function ConveyorMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
const { projectId } = useParams();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventData) {
|
||||
@@ -52,7 +56,8 @@ function ConveyorMechanics() {
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,7 +71,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -85,7 +90,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -99,7 +104,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -115,7 +120,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -131,7 +136,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -145,7 +150,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
@@ -161,7 +166,7 @@ function ConveyorMechanics() {
|
||||
updateBackend(
|
||||
selectedProduct.productName,
|
||||
selectedProduct.productUuid,
|
||||
projectId ||'',
|
||||
projectId || '',
|
||||
event
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,22 +3,25 @@ import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import ProcessAction from "../actions/ProcessAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
function MachineMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateAction } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getPointByUuid, updateAction } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -48,7 +51,8 @@ function MachineMechanics() {
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,25 @@ import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import Trigger from "../trigger/Trigger";
|
||||
import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
function RoboticArmMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction, } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction, } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -58,6 +61,7 @@ function RoboticArmMechanics() {
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -5,21 +5,24 @@ import Trigger from "../trigger/Trigger";
|
||||
import StorageAction from "../actions/StorageAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
|
||||
import * as THREE from 'three';
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
function StorageMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, updateAction } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getPointByUuid, updateAction } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const updateSelectedPointData = () => {
|
||||
@@ -66,7 +69,8 @@ function StorageMechanics() {
|
||||
productName: productName,
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,22 +7,25 @@ import {
|
||||
useSelectedAction,
|
||||
useSelectedEventData,
|
||||
} from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import TravelAction from "../actions/TravelAction";
|
||||
import ActionsList from "../components/ActionsList";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
function VehicleMechanics() {
|
||||
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
|
||||
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -54,6 +57,7 @@ function VehicleMechanics() {
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import { AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../../../icons/Expo
|
||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||
import { useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
|
||||
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
|
||||
|
||||
type TriggerProps = {
|
||||
selectedPointData?: PointsScheme | undefined;
|
||||
@@ -19,13 +20,15 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
||||
const [currentAction, setCurrentAction] = useState<string | undefined>();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { getActionByUuid, getEventByModelUuid, getPointByUuid, getTriggerByUuid, addTrigger, removeTrigger, updateTrigger, renameTrigger, getProductById, } = useProductStore();
|
||||
const { productStore } = useSceneContext();
|
||||
const { getActionByUuid, getEventByModelUuid, getPointByUuid, getTriggerByUuid, addTrigger, removeTrigger, updateTrigger, renameTrigger, getProductById, } = productStore();
|
||||
const [triggers, setTriggers] = useState<TriggerSchema[]>([]);
|
||||
const [selectedTrigger, setSelectedTrigger] = useState<TriggerSchema | undefined>();
|
||||
const [activeOption, setActiveOption] = useState<"onComplete" | "onStart" | "onStop" | "delay" | "onError">("onComplete");
|
||||
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||
const { selectedAction } = useSelectedAction();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -53,6 +56,7 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
|
||||
productUuid: productUuid,
|
||||
projectId: projectId,
|
||||
eventDatas: eventData,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,10 @@ import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icon
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||
import { useMainProduct, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
||||
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||
import { generateUUID } from "three/src/math/MathUtils";
|
||||
import RenderOverlay from "../../../templates/Overlay";
|
||||
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
|
||||
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
|
||||
import { deleteEventDataApi } from "../../../../services/simulation/products/deleteEventDataApi";
|
||||
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
|
||||
import { deleteProductApi } from "../../../../services/simulation/products/deleteProductApi";
|
||||
@@ -19,6 +17,8 @@ import { useCompareStore, useSaveVersion, } from "../../../../store/builder/stor
|
||||
import { useToggleStore } from "../../../../store/useUIToggleStore";
|
||||
import { useProductContext } from "../../../../modules/simulation/products/productContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
|
||||
interface Event {
|
||||
modelName: string;
|
||||
@@ -39,17 +39,19 @@ const List: React.FC<ListProps> = ({ val }) => {
|
||||
|
||||
const Simulations: React.FC = () => {
|
||||
const productsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, getProductById, } = useProductStore();
|
||||
const { eventStore, productStore } = useSceneContext();
|
||||
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, getProductById, } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
||||
const { getEventByModelUuid } = useEventsStore();
|
||||
const { getEventByModelUuid } = eventStore();
|
||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const [openObjects, setOpenObjects] = useState(true);
|
||||
const [processes, setProcesses] = useState<Event[][]>();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
const { projectId } = useParams();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { comparePopUp, setComparePopUp } = useCompareStore();
|
||||
const { setIsVersionSaved } = useSaveVersion();
|
||||
|
||||
@@ -67,6 +69,7 @@ const Simulations: React.FC = () => {
|
||||
productName: name,
|
||||
productUuid: id,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
};
|
||||
|
||||
@@ -99,13 +102,14 @@ const Simulations: React.FC = () => {
|
||||
removeProduct(productUuid);
|
||||
deleteProductApi({
|
||||
productUuid,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId
|
||||
});
|
||||
};
|
||||
|
||||
const handleRenameProduct = (productUuid: string, newName: string) => {
|
||||
renameProduct(productUuid, newName);
|
||||
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
|
||||
renameProductApi({ productName: newName, productUuid, projectId: projectId || '', versionId: selectedVersion?.versionId || '' });
|
||||
if (selectedProduct.productUuid === productUuid) {
|
||||
setSelectedProduct(productUuid, newName);
|
||||
setMainProduct(productUuid, newName);
|
||||
@@ -118,6 +122,7 @@ const Simulations: React.FC = () => {
|
||||
deleteEventDataApi({
|
||||
productUuid: selectedProduct.productUuid,
|
||||
modelUuid: selectedAsset.modelUuid,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId: projectId,
|
||||
});
|
||||
removeEvent(selectedProduct.productUuid, selectedAsset.modelUuid);
|
||||
@@ -265,7 +270,8 @@ const Simulations: React.FC = () => {
|
||||
addEvent,
|
||||
selectedProduct,
|
||||
clearSelectedAsset,
|
||||
projectId: projectId || ''
|
||||
projectId: projectId || '',
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
});
|
||||
} else {
|
||||
handleRemoveEventFromProduct();
|
||||
|
||||
@@ -1,147 +1,156 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
AddIcon,
|
||||
ArrowIcon,
|
||||
CloseIcon,
|
||||
KebabIcon,
|
||||
LocationIcon,
|
||||
AddIcon,
|
||||
ArrowIcon,
|
||||
CloseIcon,
|
||||
KebabIcon,
|
||||
LocationIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||
import { useVersionStore } from "../../../../store/builder/store";
|
||||
import { generateUniqueId } from "../../../../functions/generateUniqueId";
|
||||
import { useVersionHistoryStore } from "../../../../store/builder/useVersionHistoryStore";
|
||||
import { useSubModuleStore } from "../../../../store/useModuleStore";
|
||||
import useVersionHistoryVisibleStore from "../../../../store/builder/store";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getVersionDataApi } from "../../../../services/factoryBuilder/versionControl/getVersionDataApi";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
|
||||
const VersionHistory = () => {
|
||||
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
||||
const { versions, addVersion, setVersions, updateVersion } =
|
||||
useVersionStore();
|
||||
const [selectedVersion, setSelectedVersion] = useState(
|
||||
versions.length > 0 ? versions[0] : null
|
||||
);
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { versionHistory, setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const addNewVersion = () => {
|
||||
const newVersion = {
|
||||
id: generateUniqueId(),
|
||||
versionLabel: `v${versions.length + 1}.0`,
|
||||
versionName: "",
|
||||
timestamp: new Date().toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
}),
|
||||
savedBy: userName,
|
||||
const addNewVersion = () => {
|
||||
setCreateNewVersion(true);
|
||||
};
|
||||
|
||||
const newVersions = [newVersion, ...versions];
|
||||
addVersion(newVersion);
|
||||
setSelectedVersion(newVersion);
|
||||
setVersions(newVersions);
|
||||
};
|
||||
const handleSelectVersion = (version: Version) => {
|
||||
if (!projectId) return;
|
||||
|
||||
const handleSelectVersion = (version: any) => {
|
||||
setSelectedVersion(version);
|
||||
const reordered = [version, ...versions.filter((v) => v.id !== version.id)];
|
||||
setVersions(reordered);
|
||||
};
|
||||
getVersionDataApi(projectId, version.versionId).then((verdionData) => {
|
||||
setSelectedVersion(version);
|
||||
console.log(verdionData);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
};
|
||||
|
||||
const handleVersionNameChange = (newName: string, versionId: string) => {
|
||||
const updated = versions.map((v) =>
|
||||
v.id === versionId ? { ...v, versionName: newName } : v
|
||||
);
|
||||
setVersions(updated);
|
||||
updateVersion(versionId, { versionName: newName });
|
||||
};
|
||||
const handleVersionNameChange = (newName: string, versionId: string) => {
|
||||
|
||||
return (
|
||||
<div className="version-history-container">
|
||||
{/* Header */}
|
||||
<div className="version-history-header">
|
||||
<div className="version-history-title">Version History</div>
|
||||
<div className="version-history-icons">
|
||||
<button
|
||||
id="add-version"
|
||||
className="icon add-icon"
|
||||
onClick={addNewVersion}
|
||||
>
|
||||
<AddIcon />
|
||||
</button>
|
||||
<div id="version-kebab" className="icon kebab-icon">
|
||||
<KebabIcon />
|
||||
</div>
|
||||
<div id="version-close" className="icon close-icon">
|
||||
<CloseIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
};
|
||||
|
||||
{/* Shortcut Info */}
|
||||
<div className="version-history-shortcut-info">
|
||||
<div className="info-icon">i</div>
|
||||
<div className="shortcut-text">
|
||||
Press Ctrl + Alt + S to add to version history while editing
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current Version Display */}
|
||||
{selectedVersion && (
|
||||
<div className="version-history-location">
|
||||
<div className="location-label">
|
||||
<LocationIcon />
|
||||
</div>
|
||||
<div className="location-details">
|
||||
<div className="current-version">
|
||||
Current Version ({selectedVersion.versionLabel})
|
||||
</div>
|
||||
<div className="saved-history-count">
|
||||
{versions.length} Saved History
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Versions List */}
|
||||
<div className="saved-versions-list">
|
||||
{versions.length === 0 ? (
|
||||
<div className="no-versions-message">No saved versions</div>
|
||||
) : (
|
||||
versions.map((version) => (
|
||||
<button
|
||||
key={version.id}
|
||||
className="saved-version"
|
||||
onClick={() => handleSelectVersion(version)}
|
||||
>
|
||||
<div className="version-name">{version.versionLabel}</div>
|
||||
<div className="version-details">
|
||||
<div className="details">
|
||||
<span className="timestamp">
|
||||
{version.versionName ? (
|
||||
<RenameInput
|
||||
value={version.versionName}
|
||||
onRename={(newName) =>
|
||||
handleVersionNameChange(newName, version.id)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<RenameInput
|
||||
value={version.timestamp}
|
||||
onRename={(newName) =>
|
||||
handleVersionNameChange(newName, version.id)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span className="saved-by">
|
||||
<div className="user-profile">{version.savedBy[0]}</div>
|
||||
<div className="user-name">{version.savedBy}</div>
|
||||
</span>
|
||||
return (
|
||||
<div className="version-history-container">
|
||||
{/* Header */}
|
||||
<div className="version-history-header">
|
||||
<div className="version-history-title">Version History</div>
|
||||
<div className="version-history-icons">
|
||||
<button
|
||||
id="add-version"
|
||||
className="icon add-icon"
|
||||
onClick={addNewVersion}
|
||||
>
|
||||
<AddIcon />
|
||||
</button>
|
||||
<div id="version-kebab" className="icon kebab-icon">
|
||||
<KebabIcon />
|
||||
</div>
|
||||
<div
|
||||
id="version-close"
|
||||
className="icon close-icon"
|
||||
onClick={() => {
|
||||
setSubModule("properties");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</div>
|
||||
</div>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
|
||||
{/* Shortcut Info */}
|
||||
<div className="version-history-shortcut-info">
|
||||
<div className="info-icon">i</div>
|
||||
<div className="shortcut-text">
|
||||
Press Ctrl + Alt + S to add to version history while editing
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current Version Display */}
|
||||
{selectedVersion && (
|
||||
<div className="version-history-location">
|
||||
<div className="location-label">
|
||||
<LocationIcon />
|
||||
</div>
|
||||
<div className="location-details">
|
||||
<div className="current-version">
|
||||
Current Version ({selectedVersion.version})
|
||||
</div>
|
||||
<div className="saved-history-count">
|
||||
{versionHistory.length} Saved History
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Versions List */}
|
||||
<div className="saved-versions-list">
|
||||
{versionHistory.length === 0 ? (
|
||||
<div className="no-versions-message">No saved versions</div>
|
||||
) : (
|
||||
versionHistory.map((version) => {
|
||||
const key = `version-${version.versionId}`;
|
||||
return (
|
||||
<VersionHistoryItem
|
||||
key={key}
|
||||
version={version}
|
||||
onSelect={handleSelectVersion}
|
||||
onRename={handleVersionNameChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VersionHistory;
|
||||
|
||||
type VersionHistoryItemProps = {
|
||||
version: Version;
|
||||
onSelect: (version: Version) => void;
|
||||
onRename: (newName: string, versionId: string) => void;
|
||||
};
|
||||
|
||||
const VersionHistoryItem: React.FC<VersionHistoryItemProps> = ({ version, onSelect, onRename }) => {
|
||||
return (
|
||||
<button
|
||||
className="saved-version"
|
||||
>
|
||||
<div
|
||||
className="version-name"
|
||||
onClick={() => onSelect(version)}
|
||||
>
|
||||
v {version.version}
|
||||
</div>
|
||||
<div className="version-details">
|
||||
<div className="details">
|
||||
<span className="timestamp">
|
||||
<RenameInput
|
||||
value={version.versionName ? version.versionName : version.timeStamp}
|
||||
onRename={(newName) => onRename(newName, version.versionId)}
|
||||
/>
|
||||
</span>
|
||||
<span className="saved-by">
|
||||
<div className="user-profile">{version.createdBy[0]}</div>
|
||||
<div className="user-name">{version.createdBy}</div>
|
||||
</span>
|
||||
</div>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,148 +1,100 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { useVersionStore } from "../../../../store/builder/store";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
CloseIcon,
|
||||
FinishEditIcon,
|
||||
RenameVersionIcon,
|
||||
SaveIcon,
|
||||
SaveVersionIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import RenderOverlay from "../../../templates/Overlay";
|
||||
import { useVersionHistoryStore } from "../../../../store/builder/useVersionHistoryStore";
|
||||
import { createVersionApi } from "../../../../services/factoryBuilder/versionControl/addVersionApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
|
||||
const VersionSaved = () => {
|
||||
const { versions, updateVersion } = useVersionStore();
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [shouldDismiss, setShouldDismiss] = useState(false);
|
||||
const [showNotification, setShowNotification] = useState(false);
|
||||
const [newName, setNewName] = useState("");
|
||||
const { versionHistory, addVersion, createNewVersion, setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { setSelectedVersion } = selectedVersionStore();
|
||||
const [newName, setNewName] = useState(new Date().toLocaleString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
}));
|
||||
const [description, setDescription] = useState("");
|
||||
const [showEditedFinish, setShowEditedFinish] = useState(false);
|
||||
const [editedVersionName, setEditedVersionName] = useState("");
|
||||
const prevVersionCount = useRef(versions.length);
|
||||
const dismissTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [showSaveFinish, setSaveFinish] = useState(false);
|
||||
const { projectId } = useParams();
|
||||
const { userId } = getUserData();
|
||||
|
||||
const latestVersion = versions?.[0];
|
||||
const latestVersion = versionHistory?.[0];
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (versions.length > prevVersionCount.current && latestVersion) {
|
||||
setShowNotification(true);
|
||||
setShouldDismiss(false);
|
||||
setIsEditing(false);
|
||||
setNewName(latestVersion.versionName ?? "");
|
||||
setDescription(latestVersion.description ?? "");
|
||||
setEditedVersionName(latestVersion.versionName ?? ""); // Initialize editedVersionName
|
||||
|
||||
if (!isEditing) {
|
||||
startDismissTimer();
|
||||
}
|
||||
|
||||
prevVersionCount.current = versions.length;
|
||||
} else if (versions.length < prevVersionCount.current) {
|
||||
prevVersionCount.current = versions.length;
|
||||
if (createNewVersion) {
|
||||
const defaultName = new Date().toLocaleString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
});
|
||||
setNewName(defaultName);
|
||||
setDescription("");
|
||||
}
|
||||
}, [versions, isEditing, latestVersion]);
|
||||
}, [createNewVersion]);
|
||||
|
||||
const startDismissTimer = (delay = 5000) => {
|
||||
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
|
||||
dismissTimerRef.current = setTimeout(() => {
|
||||
setShouldDismiss(true);
|
||||
}, delay);
|
||||
};
|
||||
const handleSave = () => {
|
||||
if (!latestVersion || !projectId) return;
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldDismiss) {
|
||||
const timer = setTimeout(() => setShowNotification(false), 200);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [shouldDismiss]);
|
||||
const updatedName = (newName.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
|
||||
const updatedDescription = (description.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
|
||||
|
||||
const handleEditName = () => {
|
||||
if (!latestVersion) return;
|
||||
createVersionApi(projectId, userId, latestVersion.versionId, updatedName, updatedDescription).then((data) => {
|
||||
setSaveFinish(true);
|
||||
setCreateNewVersion(false);
|
||||
|
||||
setIsEditing(true);
|
||||
setNewName(latestVersion.versionName ?? "");
|
||||
setDescription(latestVersion.description ?? "");
|
||||
if (dismissTimerRef.current) {
|
||||
clearTimeout(dismissTimerRef.current);
|
||||
dismissTimerRef.current = null;
|
||||
}
|
||||
};
|
||||
addVersion({
|
||||
version: data.version,
|
||||
versionId: data.versionId,
|
||||
versionName: data.versionName,
|
||||
versionDescription: data.description,
|
||||
timeStamp: data.createdAt,
|
||||
createdBy: data.createdBy.userName
|
||||
})
|
||||
|
||||
const handleFinishEdit = () => {
|
||||
if (!latestVersion) return;
|
||||
setSelectedVersion({
|
||||
version: data.version,
|
||||
versionId: data.versionId,
|
||||
versionName: data.versionName,
|
||||
versionDescription: data.description,
|
||||
timeStamp: data.createdAt,
|
||||
createdBy: data.createdBy.userName
|
||||
})
|
||||
|
||||
const updatedName =
|
||||
(newName.trim() || latestVersion.versionName) ?? latestVersion.timestamp;
|
||||
updateVersion(latestVersion.id, {
|
||||
versionName: updatedName,
|
||||
description,
|
||||
});
|
||||
|
||||
setEditedVersionName(updatedName);
|
||||
setIsEditing(false);
|
||||
setShowEditedFinish(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setShowEditedFinish(false);
|
||||
}, 5000);
|
||||
|
||||
startDismissTimer();
|
||||
setTimeout(() => {
|
||||
setSaveFinish(false);
|
||||
}, 3000);
|
||||
}).catch((err) => {
|
||||
setSaveFinish(false);
|
||||
setCreateNewVersion(false);
|
||||
})
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setIsEditing(false);
|
||||
startDismissTimer();
|
||||
setSaveFinish(false);
|
||||
setCreateNewVersion(false);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setShouldDismiss(true);
|
||||
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
|
||||
};
|
||||
|
||||
if (!showNotification || !latestVersion) return null;
|
||||
if (!latestVersion) return null;
|
||||
|
||||
return (
|
||||
<div className={`versionSaved ${shouldDismiss ? "dismissing" : ""}`}>
|
||||
{!isEditing && !showEditedFinish && (
|
||||
<div className="versionSaved-wrapper">
|
||||
<div className="version-header">
|
||||
<div className="header-wrapper">
|
||||
<div className="icon">
|
||||
<SaveIcon />
|
||||
</div>
|
||||
<span>Saved New Version</span>
|
||||
</div>
|
||||
<button className="close-btn" onClick={handleClose}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="version-details">
|
||||
<SaveVersionIcon />
|
||||
<div className="details">
|
||||
<div className="details-wrapper">
|
||||
New Version Created {latestVersion.versionLabel}{" "}
|
||||
{latestVersion.timestamp.toUpperCase()}
|
||||
</div>
|
||||
<button onClick={handleEditName}>Edit name</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isEditing && (
|
||||
<div className={`versionSaved`}>
|
||||
{createNewVersion &&
|
||||
<RenderOverlay>
|
||||
<div className="edit-version-popup-wrapper">
|
||||
<div className="details-wrapper-popup-container">
|
||||
<div className="header-wrapper">
|
||||
<RenameVersionIcon />
|
||||
<div className="label">Rename Version</div>
|
||||
<div className="label">Create Version</div>
|
||||
</div>
|
||||
<div className="details-wrapper">
|
||||
<div className="version-name">
|
||||
@@ -153,13 +105,10 @@ const VersionSaved = () => {
|
||||
placeholder="Enter new version name"
|
||||
/>
|
||||
<div className="label">
|
||||
by @{latestVersion.savedBy}{" "}
|
||||
{new Date(latestVersion.timestamp).toLocaleString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "2-digit",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
by @{latestVersion.createdBy}{" "}{new Date(latestVersion.timeStamp).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,16 +125,16 @@ const VersionSaved = () => {
|
||||
<button className="cancel" onClick={handleCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
<button className="save" onClick={handleFinishEdit}>
|
||||
<button className="save" onClick={handleSave}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RenderOverlay>
|
||||
)}
|
||||
}
|
||||
|
||||
{showEditedFinish && (
|
||||
{showSaveFinish && (
|
||||
<RenderOverlay>
|
||||
<div className="finishEdit-version-popup-wrapper">
|
||||
<div className="finishEdit-wrapper-popup-container">
|
||||
@@ -193,7 +142,7 @@ const VersionSaved = () => {
|
||||
<FinishEditIcon />
|
||||
</div>
|
||||
<div className="versionname">
|
||||
{editedVersionName || latestVersion.versionName}
|
||||
{newName.trim()}
|
||||
</div>
|
||||
<div className="success-message">Saved Successfully!</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,9 @@ import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -23,12 +26,12 @@ const BarChartInput = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,15 +39,15 @@ const BarChartInput = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.log("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,7 +58,7 @@ const BarChartInput = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
@@ -66,15 +69,16 @@ const BarChartInput = (props: Props) => {
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -95,15 +99,15 @@ const BarChartInput = (props: Props) => {
|
||||
inputName: any
|
||||
) => {
|
||||
// const userId = localStorage.getItem("userId");
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// }
|
||||
// }
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
@@ -112,43 +116,49 @@ const BarChartInput = (props: Props) => {
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
|
||||
// }
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
},
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId);
|
||||
|
||||
|
||||
if(response.message==="Widget updated successfully"){
|
||||
return true;
|
||||
}else{
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -163,7 +173,7 @@ const BarChartInput = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -180,7 +190,7 @@ const BarChartInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -7,6 +7,9 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -22,11 +25,12 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
|
||||
const isSelected = () => {};
|
||||
const { projectId } = useParams()
|
||||
|
||||
const isSelected = () => { };
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -38,7 +42,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -53,14 +57,22 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -85,34 +97,51 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
|
||||
console.error("There was an error!", error);
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId)
|
||||
// console.log('response: ', response);
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
|
||||
// } as any
|
||||
// );
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// console.log("Unexpected response:", response);
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
|
||||
@@ -7,6 +7,9 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -22,9 +25,9 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,7 +39,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -52,14 +55,22 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -84,34 +95,51 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
console.error("There was an error!", error);
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId)
|
||||
// console.log('response: ', response);
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// console.log("Unexpected response:", response);
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
|
||||
@@ -23,20 +23,20 @@
|
||||
// try {
|
||||
// const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
// if (response.status === 200) {
|
||||
// console.log('dropdown data:', response.data);
|
||||
//
|
||||
// setDropDownData(response.data)
|
||||
// } else {
|
||||
// console.log('Unexpected response:', response);
|
||||
//
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('There was an error!', error);
|
||||
//
|
||||
// }
|
||||
// };
|
||||
// fetchZoneData();
|
||||
// }, []);
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log(selections);
|
||||
//
|
||||
// }, [selections])
|
||||
|
||||
// const handleSelect = (inputKey: string, selectedData: { name: string, fields: string } | null) => {
|
||||
@@ -125,6 +125,9 @@ import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -139,11 +142,12 @@ const LineGrapInput = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -151,15 +155,15 @@ const LineGrapInput = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -170,7 +174,7 @@ const LineGrapInput = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
@@ -181,15 +185,16 @@ const LineGrapInput = (props: Props) => {
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -210,15 +215,16 @@ const LineGrapInput = (props: Props) => {
|
||||
inputName: any
|
||||
) => {
|
||||
// const userId = localStorage.getItem("userId");
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// }
|
||||
// }
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
@@ -228,42 +234,46 @@ const LineGrapInput = (props: Props) => {
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
},
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -278,7 +288,7 @@ const LineGrapInput = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -295,7 +305,7 @@ const LineGrapInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -9,6 +9,9 @@ import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -23,12 +26,12 @@ const PieChartInput = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,15 +39,15 @@ const PieChartInput = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,7 +58,7 @@ const PieChartInput = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
@@ -66,15 +69,16 @@ const PieChartInput = (props: Props) => {
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -96,15 +100,15 @@ const PieChartInput = (props: Props) => {
|
||||
) => {
|
||||
|
||||
// const userId = localStorage.getItem("userId");
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// }
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
@@ -114,42 +118,48 @@ const PieChartInput = (props: Props) => {
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
},
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -164,7 +174,7 @@ const PieChartInput = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -181,7 +191,7 @@ const PieChartInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -9,6 +9,9 @@ import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -23,12 +26,12 @@ const Progress1Input = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,15 +39,15 @@ const Progress1Input = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,7 +58,7 @@ const Progress1Input = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
@@ -66,15 +69,16 @@ const Progress1Input = (props: Props) => {
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -95,15 +99,15 @@ const Progress1Input = (props: Props) => {
|
||||
inputName: any
|
||||
) => {
|
||||
// const userId = localStorage.getItem("userId");
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// }
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
@@ -113,42 +117,47 @@ const Progress1Input = (props: Props) => {
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
},
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -163,7 +172,7 @@ const Progress1Input = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -23,12 +26,12 @@ const Progress2Input = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,15 +39,15 @@ const Progress2Input = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,7 +58,7 @@ const Progress2Input = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`,
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
@@ -66,15 +69,16 @@ const Progress2Input = (props: Props) => {
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -95,15 +99,16 @@ const Progress2Input = (props: Props) => {
|
||||
inputName: any
|
||||
) => {
|
||||
// const userId = localStorage.getItem("userId");
|
||||
// let newWidget = {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// }
|
||||
// }
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
@@ -113,42 +118,48 @@ const Progress2Input = (props: Props) => {
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
},
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId);
|
||||
|
||||
if(response.message==="Widget updated successfully"){
|
||||
|
||||
return true;
|
||||
}else{
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -163,7 +174,7 @@ const Progress2Input = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -22,9 +25,9 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -36,7 +39,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -51,14 +54,22 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -82,33 +93,45 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
{
|
||||
organization: organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId)
|
||||
// console.log('response: ', response);
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -140,7 +163,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
// console.log("name change requested", name);
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -21,8 +22,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,7 +35,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -57,7 +57,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -85,7 +85,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
|
||||
const Widget3InputCard3D = () => {
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
@@ -19,8 +20,7 @@ const Widget3InputCard3D = () => {
|
||||
>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -33,7 +33,7 @@ const Widget3InputCard3D = () => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -55,7 +55,7 @@ const Widget3InputCard3D = () => {
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -82,7 +82,7 @@ const Widget3InputCard3D = () => {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
@@ -97,7 +97,7 @@ const Widget3InputCard3D = () => {
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -21,8 +22,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -35,7 +35,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
@@ -57,7 +57,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
@@ -85,7 +85,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
@@ -100,7 +100,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -44,7 +44,7 @@ const Design = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Styles", styles);
|
||||
// console.log("Styles", styles);
|
||||
}, [styles]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,6 +6,7 @@ import RegularDropDown from "../ui/inputs/RegularDropDown";
|
||||
import { access } from "fs";
|
||||
import MultiEmailInvite from "../ui/inputs/MultiEmailInvite";
|
||||
import { useActiveUsers } from "../../store/builder/store";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
|
||||
interface UserListTemplateProps {
|
||||
user: User;
|
||||
@@ -59,10 +60,10 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
setUserManagement,
|
||||
}) => {
|
||||
const { activeUsers } = useActiveUsers();
|
||||
const { userName } = getUserData();
|
||||
useEffect(() => {
|
||||
console.log("activeUsers: ", activeUsers);
|
||||
// console.log("activeUsers: ", activeUsers);
|
||||
}, [activeUsers]);
|
||||
const userName = localStorage.getItem("userName") || "Anonymous";
|
||||
const users = [
|
||||
{
|
||||
name: "Alice Johnson",
|
||||
@@ -140,7 +141,7 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
<div className="users-list-container">
|
||||
<div className="you-container">
|
||||
<div className="your-name">
|
||||
<div className="user-profile">{userName[0].toUpperCase()}</div>
|
||||
<div className="user-profile">{userName && userName[0].toUpperCase()}</div>
|
||||
{userName}
|
||||
</div>
|
||||
<div className="indicater">you</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useParams } from "react-router-dom";
|
||||
import { useProjectName } from "../../store/builder/store";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { useComparisonProduct } from "../../store/simulation/useSimulationStore";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
|
||||
interface LoadingPageProps {
|
||||
progress: number; // Expect progress as a percentage (0-100)
|
||||
@@ -14,42 +15,28 @@ const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
|
||||
const { projectName, setProjectName } = useProjectName();
|
||||
const { projectId } = useParams();
|
||||
const { comparisonProduct } = useComparisonProduct();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
const validatedProgress = Math.min(100, Math.max(0, progress));
|
||||
const generateThumbnail = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
try {
|
||||
if (!email || !userId) {
|
||||
console.error("User data not found in localStorage");
|
||||
return;
|
||||
}
|
||||
|
||||
const emailParts = email.split("@");
|
||||
if (emailParts.length < 2) {
|
||||
console.error("Invalid email format");
|
||||
return;
|
||||
}
|
||||
|
||||
const domainParts = emailParts[1].split(".");
|
||||
const Organization = domainParts[0];
|
||||
const projects = await getAllProjects(userId, Organization);
|
||||
const filterProject = projects?.Projects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
);
|
||||
|
||||
setProjectName(filterProject.projectName);
|
||||
} catch {}
|
||||
};
|
||||
useEffect(() => {
|
||||
generateThumbnail();
|
||||
if (!userId) return;
|
||||
|
||||
getAllProjects(userId, organization).then((projects) => {
|
||||
const filterProject = projects?.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId);
|
||||
if (filterProject) {
|
||||
setProjectName(filterProject.projectName);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<RenderOverlay>
|
||||
<div
|
||||
className={`loading-wrapper ${
|
||||
comparisonProduct != null ? "comparisionLoading" : ""
|
||||
}`}
|
||||
className={`loading-wrapper ${comparisonProduct != null ? "comparisionLoading" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="loading-container">
|
||||
<div className="project-name">{projectName}</div>
|
||||
|
||||
@@ -7,130 +7,102 @@ import { useProjectName, useSocketStore } from "../../store/builder/store";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { updateProject } from "../../services/dashboard/updateProject";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
|
||||
const FileMenu: React.FC = () => {
|
||||
const [openMenu, setOpenMenu] = useState(false);
|
||||
const containerRef = useRef<HTMLButtonElement>(null);
|
||||
let clickTimeout: NodeJS.Timeout | null = null;
|
||||
const { projectName, setProjectName } = useProjectName();
|
||||
const { dashBoardSocket } = useSocketStore();
|
||||
const { projectId } = useParams();
|
||||
const [openMenu, setOpenMenu] = useState(false);
|
||||
const containerRef = useRef<HTMLButtonElement>(null);
|
||||
let clickTimeout: NodeJS.Timeout | null = null;
|
||||
const { projectName, setProjectName } = useProjectName();
|
||||
const { dashBoardSocket } = useSocketStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization, email } = getUserData();
|
||||
|
||||
const handleClick = () => {
|
||||
if (clickTimeout) return;
|
||||
setOpenMenu((prev) => !prev);
|
||||
clickTimeout = setTimeout(() => {
|
||||
clickTimeout = null;
|
||||
}, 800);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
containerRef.current &&
|
||||
!containerRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setOpenMenu(false);
|
||||
}
|
||||
const handleClick = () => {
|
||||
if (clickTimeout) return;
|
||||
setOpenMenu((prev) => !prev);
|
||||
clickTimeout = setTimeout(() => {
|
||||
clickTimeout = null;
|
||||
}, 800);
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
containerRef.current &&
|
||||
!containerRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setOpenMenu(false);
|
||||
}
|
||||
};
|
||||
|
||||
// project
|
||||
// const [projectName, setProjectName] = useState("Demo Project");
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
// Load project name from localStorage on mount
|
||||
// useEffect(() => {
|
||||
// const savedName = localStorage.getItem("projectName");
|
||||
// if (savedName) {
|
||||
// setProjectName(savedName);
|
||||
// }
|
||||
// }, []);
|
||||
const handleProjectRename = async (projectName: string) => {
|
||||
setProjectName(projectName);
|
||||
if (!projectId) return
|
||||
|
||||
// const handleProjectRename = (newName: string) => {
|
||||
// setProjectName(newName);
|
||||
// localStorage.setItem("projectName", newName);
|
||||
// };
|
||||
const handleProjectRename = async (projectName: string) => {
|
||||
setProjectName(projectName);
|
||||
if (!projectId) return
|
||||
// localStorage.setItem("projectName", newName);
|
||||
try {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
// localStorage.setItem("projectName", newName);
|
||||
|
||||
if (!email || !userId) {
|
||||
try {
|
||||
|
||||
return;
|
||||
}
|
||||
if (!email || !userId) return;
|
||||
|
||||
const emailParts = email.split("@");
|
||||
if (emailParts.length < 2) {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
// console.log('projects: ', projects);
|
||||
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId)
|
||||
|
||||
return;
|
||||
}
|
||||
const updateProjects = {
|
||||
projectId: projectUuid,
|
||||
organization,
|
||||
userId,
|
||||
projectName,
|
||||
thumbnail: undefined
|
||||
}
|
||||
|
||||
const domainParts = emailParts[1].split(".");
|
||||
const Organization = domainParts[0];
|
||||
const projects = await getAllProjects(
|
||||
userId, Organization
|
||||
);
|
||||
console.log('projects: ', projects);
|
||||
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id
|
||||
=== projectId)
|
||||
const updateProjects = {
|
||||
projectId: projectUuid,
|
||||
organization: Organization,
|
||||
userId,
|
||||
projectName,
|
||||
thumbnail: undefined
|
||||
}
|
||||
// if (dashBoardSocket) {
|
||||
// const handleResponse = (data: any) => {
|
||||
// console.log('Project update response:', data);
|
||||
// dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
|
||||
// };
|
||||
// dashBoardSocket.on("v1-project:response:update", handleResponse);
|
||||
// dashBoardSocket.emit("v1:project:update", updateProjects);
|
||||
// }
|
||||
|
||||
// if (dashBoardSocket) {
|
||||
// const handleResponse = (data: any) => {
|
||||
// console.log('Project update response:', data);
|
||||
// dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
|
||||
// };
|
||||
|
||||
// dashBoardSocket.on("v1-project:response:update", handleResponse);
|
||||
|
||||
// dashBoardSocket.emit("v1:project:update", updateProjects);
|
||||
// }
|
||||
|
||||
//API for projects rename
|
||||
const updatedProjectName = await updateProject(
|
||||
projectId,
|
||||
userId,
|
||||
Organization,
|
||||
undefined,
|
||||
projectName
|
||||
);
|
||||
//
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
<button
|
||||
id="project-dropdown-button"
|
||||
className="project-dropdowm-container"
|
||||
ref={containerRef}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="project-name">
|
||||
<div className="icon">
|
||||
<ProjectIcon />
|
||||
</div>
|
||||
<RenameInput value={projectName} onRename={handleProjectRename} />
|
||||
</div>
|
||||
<div className="more-options-button">
|
||||
<ArrowIcon />
|
||||
{openMenu && <MenuBar setOpenMenu={setOpenMenu} />}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
//API for projects rename
|
||||
const updatedProjectName = await updateProject(
|
||||
projectId,
|
||||
userId,
|
||||
organization,
|
||||
undefined,
|
||||
projectName
|
||||
);
|
||||
//
|
||||
} catch (error) {
|
||||
console.error("Error updating project name:", error);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<button
|
||||
id="project-dropdown-button"
|
||||
className="project-dropdowm-container"
|
||||
ref={containerRef}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="project-name">
|
||||
<div className="icon">
|
||||
<ProjectIcon />
|
||||
</div>
|
||||
<RenameInput value={projectName} onRename={handleProjectRename} />
|
||||
</div>
|
||||
<div className="more-options-button">
|
||||
<ArrowIcon />
|
||||
{openMenu && <MenuBar setOpenMenu={setOpenMenu} />}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileMenu;
|
||||
|
||||
@@ -12,7 +12,7 @@ import useVersionHistoryStore from "../../store/builder/store";
|
||||
const ModuleToggle: React.FC = () => {
|
||||
const { activeModule, setActiveModule } = useModuleStore();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
const { setVersionHistory } = useVersionHistoryStore();
|
||||
const { setVersionHistoryVisible } = useVersionHistoryStore();
|
||||
|
||||
return (
|
||||
<div className="module-toggle-container">
|
||||
@@ -21,7 +21,7 @@ const ModuleToggle: React.FC = () => {
|
||||
className={`module-list ${activeModule === "builder" ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setActiveModule("builder");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft")
|
||||
? localStorage.getItem("navBarUiLeft") === "true"
|
||||
@@ -44,7 +44,7 @@ const ModuleToggle: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveModule("simulation");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft")
|
||||
? localStorage.getItem("navBarUiLeft") === "true"
|
||||
@@ -67,7 +67,7 @@ const ModuleToggle: React.FC = () => {
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveModule("visualization");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft")
|
||||
? localStorage.getItem("navBarUiLeft") === "true"
|
||||
@@ -88,7 +88,7 @@ const ModuleToggle: React.FC = () => {
|
||||
className={`module-list ${activeModule === "market" ? "active" : ""}`}
|
||||
onClick={() => {
|
||||
setActiveModule("market");
|
||||
setVersionHistory(false);
|
||||
setVersionHistoryVisible(false);
|
||||
setToggleUI(false, false);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
useFloatingWidget,
|
||||
} from "../../store/visualization/useDroppedObjectsStore";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../modules/builder/version/versionContext";
|
||||
|
||||
// Utility component
|
||||
const ToolButton = ({
|
||||
@@ -86,6 +87,8 @@ const Tools: React.FC = () => {
|
||||
|
||||
const dropdownRef = useRef<HTMLButtonElement>(null);
|
||||
const [openDrop, setOpenDrop] = useState(false);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
// 1. Set UI toggles on initial render
|
||||
@@ -250,7 +253,8 @@ const Tools: React.FC = () => {
|
||||
selectedZone,
|
||||
templates,
|
||||
visualizationSocket,
|
||||
projectId
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { getAllThreads } from "../../../services/factoryBuilder/comments/getAllThreads";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useCommentStore } from "../../../store/collaboration/useCommentStore";
|
||||
import { getRelativeTime } from "./function/getRelativeTime";
|
||||
import { useSelectedComment } from "../../../store/builder/store";
|
||||
|
||||
interface CommentThreadsProps {
|
||||
commentClicked: () => void;
|
||||
comment?: CommentSchema
|
||||
}
|
||||
|
||||
const CommentThreads: React.FC<CommentThreadsProps> = ({ commentClicked }) => {
|
||||
const CommentThreads: React.FC<CommentThreadsProps> = ({ commentClicked, comment }) => {
|
||||
const [expand, setExpand] = useState(false);
|
||||
const commentsedUsers = [{ creatorId: "1" }];
|
||||
const { userName } = getUserData();
|
||||
|
||||
const CommentDetails = {
|
||||
state: "active",
|
||||
@@ -16,26 +24,26 @@ const CommentThreads: React.FC<CommentThreadsProps> = ({ commentClicked }) => {
|
||||
createdAt: "2 hours ago",
|
||||
comment: "Thread check",
|
||||
lastUpdatedAt: "string",
|
||||
replies: [
|
||||
comments: [
|
||||
{
|
||||
replyId: "string",
|
||||
creatorId: "string",
|
||||
createdAt: "string",
|
||||
lastUpdatedAt: "string",
|
||||
reply: "string",
|
||||
comment: "string",
|
||||
},
|
||||
{
|
||||
replyId: "string",
|
||||
creatorId: "string",
|
||||
createdAt: "string",
|
||||
lastUpdatedAt: "string",
|
||||
reply: "string",
|
||||
comment: "string",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function getUsername(userId: string) {
|
||||
const UserName = "username";
|
||||
const UserName = userName?.charAt(0).toUpperCase() || "user";
|
||||
return UserName;
|
||||
}
|
||||
|
||||
@@ -48,15 +56,15 @@ const CommentThreads: React.FC<CommentThreadsProps> = ({ commentClicked }) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="comments-threads-wrapper">
|
||||
<button
|
||||
onPointerEnter={() => getDetails()}
|
||||
onPointerLeave={() => getDetails()}
|
||||
onClick={() => getDetails("clicked")}
|
||||
className={`comments-threads-container ${
|
||||
expand ? "open" : "closed"
|
||||
} unread`}
|
||||
className={`comments-threads-container ${expand ? "open" : "closed"
|
||||
} unread`}
|
||||
>
|
||||
<div className="users-commented">
|
||||
{commentsedUsers.map((val, i) => (
|
||||
@@ -70,24 +78,37 @@ const CommentThreads: React.FC<CommentThreadsProps> = ({ commentClicked }) => {
|
||||
{getUsername(val.creatorId)[0]}
|
||||
</div>
|
||||
))}
|
||||
{/* {commentsedUsers.map((val, i) => (
|
||||
<div
|
||||
className="users"
|
||||
key={val.creatorId}
|
||||
style={{
|
||||
background: getAvatarColor(i, getUsername(val.creatorId)),
|
||||
}}
|
||||
>
|
||||
{getUsername(val.creatorId)[0]}
|
||||
</div>
|
||||
))} */}
|
||||
</div>
|
||||
<div className={`last-comment-details ${expand ? "expand" : ""}`}>
|
||||
<div className="header">
|
||||
<div className="user-name">
|
||||
{getUsername(CommentDetails.creatorId)}
|
||||
{userName}
|
||||
{/* {getUsername(CommentDetails.creatorId)} */}
|
||||
</div>
|
||||
<div className="time">{CommentDetails.createdAt}</div>
|
||||
<div className="time">{comment?.createdAt && getRelativeTime(comment.createdAt)}</div>
|
||||
</div>
|
||||
<div className="message">{CommentDetails.comment}</div>
|
||||
{CommentDetails.replies.length > 0 && (
|
||||
<div className="replies">
|
||||
{CommentDetails.replies.length}{" "}
|
||||
{CommentDetails.replies.length === 1 ? "reply" : "replies"}
|
||||
<div className="message">{comment?.threadTitle}</div>
|
||||
{comment && comment?.comments.length > 0 && (
|
||||
<div className="comments">
|
||||
{comment && comment?.comments.length}{" "}
|
||||
{comment && comment?.comments.length === 1 ? "comment" : "replies"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,44 +2,181 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
||||
import { KebabIcon } from "../../icons/ExportCommonIcons";
|
||||
import { adjustHeight } from "./function/textAreaHeightAdjust";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { deleteCommentApi } from "../../../services/factoryBuilder/comments/deleteCommentApi";
|
||||
import { addCommentsApi } from "../../../services/factoryBuilder/comments/addCommentsApi";
|
||||
import { useCommentStore } from "../../../store/collaboration/useCommentStore";
|
||||
import { useSelectedComment, useSocketStore } from "../../../store/builder/store";
|
||||
import { getRelativeTime } from "./function/getRelativeTime";
|
||||
import { editThreadTitleApi } from "../../../services/factoryBuilder/comments/editThreadTitleApi";
|
||||
|
||||
|
||||
interface MessageProps {
|
||||
val: Reply | CommentSchema;
|
||||
// val: Reply | CommentSchema;
|
||||
i: number;
|
||||
setMessages?: React.Dispatch<React.SetStateAction<Reply[]>>
|
||||
setIsEditable?: React.Dispatch<React.SetStateAction<boolean>>
|
||||
setEditedThread?: React.Dispatch<React.SetStateAction<boolean>>
|
||||
setMode?: React.Dispatch<React.SetStateAction<'create' | 'edit' | null>>
|
||||
isEditable?: boolean;
|
||||
isEditableThread?: boolean
|
||||
editedThread?: boolean;
|
||||
mode?: 'create' | 'edit' | null
|
||||
}
|
||||
|
||||
const Messages: React.FC<MessageProps> = ({ val, i }) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEditable, setEditedThread, editedThread, isEditableThread, setMode }) => {
|
||||
|
||||
const { comments, updateComment, updateReply, removeReply } = useCommentStore();
|
||||
const [openOptions, setOpenOptions] = useState(false);
|
||||
const { projectId } = useParams();
|
||||
const { threadSocket } = useSocketStore();
|
||||
const { userName, userId, organization } = getUserData();
|
||||
const [isEditComment, setIsEditComment] = useState(false)
|
||||
|
||||
const { selectedComment, setCommentPositionState } = useSelectedComment();
|
||||
|
||||
// input
|
||||
const [value, setValue] = useState<string>(
|
||||
"reply" in val ? val.reply : val.comment
|
||||
"comment" in val ? val.comment : val.threadTitle
|
||||
);
|
||||
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const currentUser = "1";
|
||||
|
||||
const UserName = "username";
|
||||
// const UserName = "username";
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) adjustHeight(textareaRef.current);
|
||||
}, [value]);
|
||||
|
||||
function handleCancelAction() {
|
||||
setIsEditing(false);
|
||||
setCommentPositionState(null)
|
||||
setIsEditable && setIsEditable(true);
|
||||
setIsEditComment(false)
|
||||
}
|
||||
|
||||
function handleSaveAction() {
|
||||
setIsEditing(false);
|
||||
const handleSaveAction = async () => {
|
||||
|
||||
if (!projectId) return
|
||||
|
||||
if (isEditableThread && editedThread) {
|
||||
try {
|
||||
// const editThreadTitle = await editThreadTitleApi(projectId, (val as CommentSchema).threadId, value)
|
||||
// if (editThreadTitle.message == "ThreadTitle updated Successfully") {
|
||||
// const editedThread: CommentSchema = {
|
||||
// state: 'active',
|
||||
// threadId: editThreadTitle.data.replyId,
|
||||
// creatorId: userId,
|
||||
// createdAt: getRelativeTime(editThreadTitle.data.createdAt),
|
||||
// threadTitle: value,
|
||||
// lastUpdatedAt: new Date().toISOString(),
|
||||
// position: editThreadTitle.data.position,
|
||||
// rotation: [0, 0, 0],
|
||||
// comments: []
|
||||
// }
|
||||
// updateComment((val as CommentSchema).threadId, editedThread)
|
||||
// }
|
||||
// projectId, userId, threadTitle, organization, threadId
|
||||
const threadEdit = {
|
||||
projectId,
|
||||
userId,
|
||||
threadTitle: value,
|
||||
organization,
|
||||
threadId: (val as CommentSchema).threadId
|
||||
}
|
||||
|
||||
threadSocket.emit('v1:thread:updateTitle', threadEdit)
|
||||
} catch {
|
||||
}
|
||||
} else {
|
||||
|
||||
if (mode === "edit") {
|
||||
try {
|
||||
// const editComments = await addCommentsApi(projectId, value, selectedComment?.threadId, (val as Reply).replyId)
|
||||
//
|
||||
// const commentData = {
|
||||
// replyId: `${editComments.data?.replyId}`,
|
||||
// creatorId: `${userId}`,
|
||||
// createdAt: getRelativeTime(editComments.data?.createdAt),
|
||||
// lastUpdatedAt: "2 hrs ago",
|
||||
// comment: value,
|
||||
// }
|
||||
|
||||
// updateReply((val as CommentSchema).threadId, (val as Reply)?.replyId, commentData);
|
||||
|
||||
if (threadSocket) {
|
||||
// projectId, userId, comment, organization, threadId
|
||||
const editComment = {
|
||||
projectId,
|
||||
userId,
|
||||
comment: value,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId,
|
||||
commentId: (val as Reply).replyId ?? ""
|
||||
}
|
||||
|
||||
|
||||
threadSocket.emit("v1-Comment:add", editComment);
|
||||
setIsEditable && setIsEditable(true);
|
||||
setEditedThread && setEditedThread(false)
|
||||
}
|
||||
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// setValue("");
|
||||
setIsEditComment(false);
|
||||
}
|
||||
|
||||
function handleDeleteAction() {
|
||||
const handleDeleteAction = async (replyID: any) => {
|
||||
if (!projectId) return
|
||||
setOpenOptions(false);
|
||||
try {
|
||||
// const deletedComment = await deleteCommentApi(projectId, selectedComment?.threadId, (val as Reply).replyId)
|
||||
//
|
||||
// if (deletedComment === "'Thread comment deleted Successfully'") {
|
||||
// setMessages && setMessages(prev => prev.filter(message => message.replyId !== replyID));
|
||||
// removeReply(val.creatorId, replyID)
|
||||
// }
|
||||
if (threadSocket && setMessages) {
|
||||
|
||||
|
||||
// projectId, userId, commentId, organization, threadId
|
||||
const deleteComment = {
|
||||
projectId,
|
||||
userId,
|
||||
commentId: (val as Reply).replyId,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
}
|
||||
|
||||
|
||||
setMessages(prev => prev.filter(message => message.replyId !== (val as Reply).replyId))
|
||||
|
||||
removeReply(selectedComment?.threadId, (val as Reply).replyId); // Remove listener after response
|
||||
threadSocket.emit("v1-Comment:delete", deleteComment);
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {
|
||||
requestAnimationFrame(() => {
|
||||
if (textareaRef.current) {
|
||||
const length = textareaRef.current.value.length;
|
||||
textareaRef.current.setSelectionRange(length, length);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{isEditing ? (
|
||||
{isEditComment ? (
|
||||
<div className="edit-container">
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
@@ -49,6 +186,7 @@ const Messages: React.FC<MessageProps> = ({ val, i }) => {
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
style={{ resize: "none" }}
|
||||
onFocus={handleFocus}
|
||||
/>
|
||||
</div>
|
||||
<div className="actions-container">
|
||||
@@ -77,16 +215,16 @@ const Messages: React.FC<MessageProps> = ({ val, i }) => {
|
||||
<div className="message-container">
|
||||
<div
|
||||
className="profile"
|
||||
style={{ background: getAvatarColor(i, UserName) }}
|
||||
style={{ background: getAvatarColor(i, userName) }}
|
||||
>
|
||||
{UserName[0]}
|
||||
{userName?.charAt(0).toUpperCase() || "user"}
|
||||
</div>
|
||||
<div className="content">
|
||||
<div className="user-details">
|
||||
<div className="user-name">{UserName}</div>
|
||||
<div className="time">{val.createdAt}</div>
|
||||
<div className="user-name">{userName}</div>
|
||||
<div className="time">{isEditableThread ? getRelativeTime(val.createdAt) : val.createdAt}</div>
|
||||
</div>
|
||||
{val.creatorId === currentUser && (
|
||||
{(val as Reply).creatorId === userId && (
|
||||
<div className="more-options">
|
||||
<button
|
||||
className="more-options-button"
|
||||
@@ -100,30 +238,33 @@ const Messages: React.FC<MessageProps> = ({ val, i }) => {
|
||||
<div className="options-list">
|
||||
<button
|
||||
className="option"
|
||||
onClick={() => {
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setMode && setMode("edit")
|
||||
setOpenOptions(false);
|
||||
setIsEditing(true);
|
||||
setEditedThread && setEditedThread(true);
|
||||
setIsEditComment(true)
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
{!(isEditableThread) && <button
|
||||
className="option"
|
||||
onClick={() => {
|
||||
handleDeleteAction();
|
||||
handleDeleteAction((val as Reply).replyId);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</button>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="message">
|
||||
{"reply" in val ? val.reply : val.comment}
|
||||
{"comment" in val ? val.comment : val.threadTitle}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -3,36 +3,67 @@ import { CloseIcon, KebabIcon } from "../../icons/ExportCommonIcons";
|
||||
import Messages from "./Messages";
|
||||
import { ExpandIcon } from "../../icons/SimulationIcons";
|
||||
import { adjustHeight } from "./function/textAreaHeightAdjust";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSelectedComment, useSocketStore } from "../../../store/builder/store";
|
||||
import { useCommentStore } from "../../../store/collaboration/useCommentStore";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import ThreadSocketResponsesDev from "../../../modules/collaboration/socket/threadSocketResponses.dev";
|
||||
import { addCommentsApi } from "../../../services/factoryBuilder/comments/addCommentsApi";
|
||||
import { deleteThreadApi } from "../../../services/factoryBuilder/comments/deleteThreadApi";
|
||||
import { createThreadApi } from "../../../services/factoryBuilder/comments/createThreadApi";
|
||||
import { getRelativeTime } from "./function/getRelativeTime";
|
||||
|
||||
|
||||
const ThreadChat: React.FC = () => {
|
||||
const { userId, organization } = getUserData();
|
||||
const [openThreadOptions, setOpenThreadOptions] = useState(false);
|
||||
const [inputActive, setInputActive] = useState(false);
|
||||
const [value, setValue] = useState<string>("");
|
||||
|
||||
const { addComment, removeReply, removeComment, addReply, comments } = useCommentStore();
|
||||
const { selectedComment, setSelectedComment, setCommentPositionState, commentPositionState, position2Dstate } = useSelectedComment()
|
||||
const [mode, setMode] = useState<'create' | 'edit' | null>('create');
|
||||
const [isEditable, setIsEditable] = useState(false);
|
||||
const [editedThread, setEditedThread] = useState(false);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [messages, setMessages] = useState<Reply[]>([])
|
||||
const { projectId } = useParams();
|
||||
const [dragging, setDragging] = useState(false);
|
||||
const [selectedDiv, setSelectedDiv] = useState(true);
|
||||
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
||||
const [position, setPosition] = useState({ x: 100, y: 100 });
|
||||
const [position, setPosition] = useState({ x: position2Dstate.x, y: position2Dstate.y });
|
||||
const { threadSocket } = useSocketStore();
|
||||
const modeRef = useRef<'create' | 'edit' | null>(null);
|
||||
const messagesRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const messages = [
|
||||
{
|
||||
replyId: "user 1",
|
||||
creatorId: "1",
|
||||
createdAt: "2 hrs ago",
|
||||
lastUpdatedAt: "2 hrs ago",
|
||||
reply:
|
||||
"reply testing reply content 1, reply testing reply content 1reply testing reply content 1",
|
||||
},
|
||||
{
|
||||
replyId: "user 2",
|
||||
creatorId: "2",
|
||||
createdAt: "2 hrs ago",
|
||||
lastUpdatedAt: "2 hrs ago",
|
||||
reply: "reply 2",
|
||||
},
|
||||
];
|
||||
useEffect(() => {
|
||||
modeRef.current = mode;
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (comments.length > 0 && selectedComment) {
|
||||
|
||||
|
||||
const allMessages = comments
|
||||
.flatMap((val: any) =>
|
||||
val?.threadId === selectedComment?.threadId ? val.comments : []
|
||||
)
|
||||
.map((c) => {
|
||||
return {
|
||||
replyId: c._id ?? "",
|
||||
creatorId: c.creatorId || c.userId,
|
||||
createdAt: c.createdAt,
|
||||
lastUpdatedAt: "1 hr ago",
|
||||
comment: c.comment,
|
||||
_id: c._id ?? "",
|
||||
};
|
||||
});
|
||||
|
||||
setMessages(allMessages);
|
||||
|
||||
}
|
||||
|
||||
}, [selectedComment])
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) adjustHeight(textareaRef.current);
|
||||
@@ -44,6 +75,19 @@ const ThreadChat: React.FC = () => {
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (event.button !== 0) return;
|
||||
// Avoid dragging if a button, icon, textarea etc. was clicked
|
||||
const target = event.target as HTMLElement;
|
||||
if (
|
||||
target.closest("button") ||
|
||||
target.closest(".sent-button") ||
|
||||
target.closest("textarea") ||
|
||||
target.closest(".options-button") ||
|
||||
target.closest(".options-list") ||
|
||||
target.closest(".send-message-wrapper") ||
|
||||
target.closest(".options delete")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = wrapperRef.current;
|
||||
if (!wrapper) return;
|
||||
@@ -58,18 +102,20 @@ const ThreadChat: React.FC = () => {
|
||||
wrapper.setPointerCapture(event.pointerId);
|
||||
};
|
||||
|
||||
const handlePointerMove = (event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (!dragging) return;
|
||||
const updatePosition = (
|
||||
{ clientX, clientY }: { clientX: number; clientY: number },
|
||||
allowMove: boolean = true
|
||||
) => {
|
||||
if (!allowMove || !wrapperRef.current) return;
|
||||
|
||||
const container = document.getElementById("work-space-three-d-canvas");
|
||||
const wrapper = wrapperRef.current;
|
||||
if (!container || !wrapper) return;
|
||||
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const wrapperRect = wrapper.getBoundingClientRect();
|
||||
|
||||
let newX = event.clientX - containerRect.left - dragOffset.x;
|
||||
let newY = event.clientY - containerRect.top - dragOffset.y;
|
||||
let newX = clientX - containerRect.left - dragOffset.x;
|
||||
let newY = clientY - containerRect.top - dragOffset.y;
|
||||
|
||||
const maxX = containerRect.width - wrapper.offsetWidth;
|
||||
const maxY = containerRect.height - wrapper.offsetHeight;
|
||||
@@ -80,6 +126,15 @@ const ThreadChat: React.FC = () => {
|
||||
setPosition({ x: newX, y: newY });
|
||||
};
|
||||
|
||||
const handlePointerMove = (e: { clientX: number; clientY: number }) => {
|
||||
if (dragging) updatePosition(e, true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updatePosition({ clientX: position.x, clientY: position.y }, true);
|
||||
}, [selectedComment]);
|
||||
|
||||
|
||||
const handlePointerUp = (event: React.PointerEvent<HTMLDivElement>) => {
|
||||
if (!dragging) return;
|
||||
setDragging(false);
|
||||
@@ -87,12 +142,146 @@ const ThreadChat: React.FC = () => {
|
||||
if (wrapper) wrapper.releasePointerCapture(event.pointerId);
|
||||
};
|
||||
|
||||
const handleCreateComments = async (e: any) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
// const createComments = await addCommentsApi(projectId, value, selectedComment?.threadId)/
|
||||
// if (createComments.message === 'Thread comments add Successfully' && createComments.data) {
|
||||
// const commentData = {
|
||||
// replyId: `${createComments.data?._id}`,
|
||||
// creatorId: `${selectedComment?.threadId}`,
|
||||
// createdAt: "2 hrs ago",
|
||||
// lastUpdatedAt: "2 hrs ago",
|
||||
// comment: value,
|
||||
// }
|
||||
// setMessages((prevMessages) => [
|
||||
// ...prevMessages,
|
||||
// commentData,
|
||||
// ]);
|
||||
// addReply(selectedComment?.threadId, commentData)
|
||||
|
||||
// }
|
||||
|
||||
if (threadSocket && mode === "create") {
|
||||
const addComment = {
|
||||
projectId,
|
||||
userId,
|
||||
comment: value,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
}
|
||||
|
||||
threadSocket.emit("v1-Comment:add", addComment);
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
setInputActive(false)
|
||||
}
|
||||
const handleDeleteThread = async () => {
|
||||
if (!projectId) return;
|
||||
try {
|
||||
// const deleteThread = await deleteThreadApi(projectId, selectedComment?.threadId)
|
||||
//
|
||||
// if (deleteThread.message === "Thread deleted Successfully") {
|
||||
// removeComment(selectedComment?.threadId)
|
||||
// setSelectedComment([])
|
||||
// }
|
||||
if (threadSocket) {
|
||||
// projectId, userId, organization, threadId
|
||||
const deleteThread = {
|
||||
projectId,
|
||||
userId,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
}
|
||||
|
||||
setSelectedComment(null)
|
||||
removeComment(selectedComment?.threadId)
|
||||
threadSocket.emit("v1:thread:delete", deleteThread);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreateThread = async (e: any) => {
|
||||
e.preventDefault();
|
||||
if (!projectId) return;
|
||||
|
||||
try {
|
||||
// try {
|
||||
// const thread = await createThreadApi(
|
||||
// projectId,
|
||||
// "active",
|
||||
// commentPositionState[0].position,
|
||||
// [0, 0, 0],
|
||||
// value
|
||||
// );
|
||||
//
|
||||
//
|
||||
|
||||
// if (thread.message === "Thread created Successfully" && thread?.threadData) {
|
||||
//
|
||||
// const comment: CommentSchema = {
|
||||
// state: 'active',
|
||||
// threadId: thread?.threadData?._id,
|
||||
// creatorId: userId,
|
||||
// createdAt: getRelativeTime(thread.threadData?.createdAt),
|
||||
// threadTitle: value,
|
||||
// lastUpdatedAt: new Date().toISOString(),
|
||||
// position: commentPositionState[0].position,
|
||||
// rotation: [0, 0, 0],
|
||||
// comments: []
|
||||
// }
|
||||
// addComment(comment);
|
||||
// setCommentPositionState(null);
|
||||
// setInputActive(false);
|
||||
// setSelectedComment([])
|
||||
// }
|
||||
|
||||
const createThread = {
|
||||
projectId,
|
||||
userId,
|
||||
organization,
|
||||
state: "active",
|
||||
position: commentPositionState.position,
|
||||
rotation: [0, 0, 0],
|
||||
threadTitle: value
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
if (threadSocket) {
|
||||
|
||||
setInputActive(false);
|
||||
threadSocket.emit("v1:thread:create", createThread);
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const scrollToBottom = () => {
|
||||
const messagesWrapper = document.querySelector(".messages-wrapper");
|
||||
if (messagesWrapper) {
|
||||
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (messages.length > 0)
|
||||
scrollToBottom();
|
||||
}, [messages])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="thread-chat-wrapper"
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerMove={(e) => handlePointerMove({ clientX: e.clientX, clientY: e.clientY })}
|
||||
onPointerUp={handlePointerUp}
|
||||
style={{
|
||||
position: "absolute",
|
||||
@@ -107,49 +296,94 @@ const ThreadChat: React.FC = () => {
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Comment</div>
|
||||
<div className="header-options">
|
||||
<button
|
||||
<div
|
||||
className="options-button"
|
||||
onClick={() => setOpenThreadOptions(!openThreadOptions)}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setOpenThreadOptions((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
<KebabIcon />
|
||||
</button>
|
||||
</div>
|
||||
{openThreadOptions && (
|
||||
<div className="options-list">
|
||||
<div className="options">Mark as Unread</div>
|
||||
<div className="options">Mark as Resolved</div>
|
||||
<div className="options delete">Delete Thread</div>
|
||||
<div className="options delete" onClick={handleDeleteThread}>Delete Thread</div>
|
||||
</div>
|
||||
)}
|
||||
<button className="close-button">
|
||||
<button className="close-button" onClick={() => {
|
||||
setSelectedComment(null)
|
||||
setCommentPositionState(null)
|
||||
}}>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="messages-wrapper">
|
||||
{messages.map((val, i) => (
|
||||
<Messages val={val as any} i={i} key={val.replyId} />
|
||||
<div className="messages-wrapper" ref={messagesRef}>
|
||||
{selectedComment &&
|
||||
<Messages val={selectedComment} i={1} key={selectedComment.creatorId} isEditableThread={true} setEditedThread={setEditedThread} editedThread={editedThread} />
|
||||
}
|
||||
{messages && messages.map((val, i) => (
|
||||
<Messages val={val as any} i={i} key={val.replyId} setMessages={setMessages} setIsEditable={setIsEditable} isEditable={isEditable} isEditableThread={false} setMode={setMode} mode={mode} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="send-message-wrapper">
|
||||
<div className={`input-container ${inputActive ? "active" : ""}`}>
|
||||
<textarea
|
||||
placeholder="type something"
|
||||
placeholder={commentPositionState && selectedComment === null ? "Type Thread Title" : "type something"}
|
||||
ref={textareaRef}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onFocus={() => setInputActive(true)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
if (commentPositionState && selectedComment === null) {
|
||||
handleCreateThread(e);
|
||||
} else {
|
||||
setMode("create");
|
||||
handleCreateComments(e);
|
||||
textareaRef.current?.blur();
|
||||
}
|
||||
setValue('')
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
textareaRef.current?.blur();
|
||||
}
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!commentPositionState && selectedComment !== null) {
|
||||
setMode("create");
|
||||
}
|
||||
}}
|
||||
autoFocus={selectedComment === null}
|
||||
onBlur={() => setInputActive(false)}
|
||||
onFocus={() => setInputActive(true)}
|
||||
style={{ resize: "none" }}
|
||||
/>
|
||||
<div className={`sent-button ${value === "" ? "disable-send-btn" : ""}`}>
|
||||
<div
|
||||
className={`sent-button ${value === "" ? "disable-send-btn" : ""}`}
|
||||
onClick={(e) => {
|
||||
if (commentPositionState && selectedComment === null) {
|
||||
handleCreateThread(e);
|
||||
} else {
|
||||
setMode("create");
|
||||
handleCreateComments(e);
|
||||
}
|
||||
setValue('')
|
||||
}}
|
||||
>
|
||||
<ExpandIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<ThreadSocketResponsesDev setMessages={setMessages} modeRef={modeRef} messages={messages} />
|
||||
</div >
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
type RelativeTimeFormatUnit = any;
|
||||
export function getRelativeTime(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
const intervals: Record<RelativeTimeFormatUnit, number> = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1,
|
||||
};
|
||||
|
||||
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
||||
|
||||
for (const key in intervals) {
|
||||
const unit = key as RelativeTimeFormatUnit;
|
||||
const diff = Math.floor(diffInSeconds / intervals[unit]);
|
||||
if (diff >= 1) {
|
||||
return rtf.format(-diff, unit);
|
||||
}
|
||||
}
|
||||
return "just now";
|
||||
}
|
||||
@@ -10,15 +10,22 @@ import {
|
||||
} from "../../../store/builder/store";
|
||||
import Search from "../inputs/Search";
|
||||
import OuterClick from "../../../utils/outerClick";
|
||||
import { useProductStore } from "../../../store/simulation/useProductStore";
|
||||
import Scene from "../../../modules/scene/scene";
|
||||
import { useComparisonProduct } from "../../../store/simulation/useSimulationStore";
|
||||
import { usePauseButtonStore, usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
import { getAllProductsApi } from "../../../services/simulation/products/getallProductsApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
const CompareLayOut = () => {
|
||||
const { comparisonProduct, setComparisonProduct, clearComparisonProduct } =
|
||||
useComparisonProduct();
|
||||
const { products } = useProductStore();
|
||||
const { clearComparisonProduct, comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
||||
const { productStore } = useSceneContext();
|
||||
const { products } = productStore();
|
||||
const { versionHistory } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion, clearSelectedVersion } = selectedVersionStore();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const [width, setWidth] = useState("50vw");
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
@@ -29,7 +36,13 @@ const CompareLayOut = () => {
|
||||
const { setIsVersionSaved } = useSaveVersion();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
const { setIsPlaying } = usePlayButtonStore();
|
||||
const { setIsPaused } = usePauseButtonStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (!comparisonProduct) {
|
||||
clearSelectedVersion();
|
||||
}
|
||||
}, [comparisonProduct])
|
||||
|
||||
OuterClick({
|
||||
contextClassName: ["displayLayouts-container", "selectLayout"],
|
||||
@@ -113,12 +126,14 @@ const CompareLayOut = () => {
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, [isResizing]);
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
const product = products.find((product) => product.productName === option);
|
||||
if (product) {
|
||||
setComparisonProduct(product.productUuid, product.productName);
|
||||
setLoadingProgress(1);
|
||||
}
|
||||
const handleSelectLayout = (version: Version) => {
|
||||
getAllProductsApi(projectId || '', version.versionId || '').then((data) => {
|
||||
if (data && data.length > 0) {
|
||||
setSelectedVersion(version);
|
||||
setComparisonProduct(data[0].productUuid, data[0].productName);
|
||||
setLoadingProgress(1);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -127,7 +142,7 @@ const CompareLayOut = () => {
|
||||
ref={wrapperRef}
|
||||
style={{ width }}
|
||||
>
|
||||
{loadingProgress == 0 && (
|
||||
{loadingProgress == 0 && selectedVersion?.versionId && (
|
||||
<button
|
||||
title="resize-canvas"
|
||||
id="compare-resize-slider-btn"
|
||||
@@ -138,7 +153,7 @@ const CompareLayOut = () => {
|
||||
</button>
|
||||
)}
|
||||
<div className="chooseLayout-container">
|
||||
{comparisonProduct && (
|
||||
{selectedVersion?.versionId && (
|
||||
<div className="compare-layout-canvas-container">
|
||||
<Suspense fallback={null}>
|
||||
<Scene layout="Comparison Layout" />
|
||||
@@ -147,35 +162,35 @@ const CompareLayOut = () => {
|
||||
)}
|
||||
|
||||
{width !== "0px" &&
|
||||
!comparisonProduct && ( // Show only if no layout selected
|
||||
!selectedVersion?.versionId && ( // Show only if no layout selected
|
||||
<div className="chooseLayout-wrapper">
|
||||
<div className="icon">
|
||||
<CompareLayoutIcon />
|
||||
</div>
|
||||
<div className="value">Choose Layout to compare</div>
|
||||
<div className="value">Choose Version to compare</div>
|
||||
<button
|
||||
className="selectLayout"
|
||||
onClick={() => setShowLayoutDropdown(!showLayoutDropdown)}
|
||||
>
|
||||
Select Layout
|
||||
Select Version
|
||||
</button>
|
||||
|
||||
{showLayoutDropdown && (
|
||||
<div className="displayLayouts-container">
|
||||
<div className="header">Layouts</div>
|
||||
<Search onChange={() => {}} />
|
||||
<div className="header">Versions</div>
|
||||
<Search onChange={() => { }} />
|
||||
<div className="layouts-container">
|
||||
{products.map((layout) => (
|
||||
{versionHistory.map((version) => (
|
||||
<button
|
||||
key={layout.productUuid}
|
||||
key={version.versionId}
|
||||
className="layout-wrapper"
|
||||
onClick={() => {
|
||||
handleSelectLayout(layout.productName);
|
||||
handleSelectLayout(version);
|
||||
setShowLayoutDropdown(false);
|
||||
}}
|
||||
>
|
||||
<LayoutIcon />
|
||||
<div className="layout">{layout.productName}</div>
|
||||
<div className="layout">{version.versionName}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -133,7 +133,7 @@ const ComparisonResult = () => {
|
||||
<div className="compare-result-container">
|
||||
<div className="header">Performance Comparison</div>
|
||||
<div className="compare-result-wrapper">
|
||||
<EnergyUsage />
|
||||
<EnergyUsage comparedProducts={comparedProducts}/>
|
||||
<div className="throughPutCard-container comparisionCard">
|
||||
<h4>Throughput (units/hr)</h4>
|
||||
<div className="layers-wrapper">
|
||||
@@ -153,7 +153,7 @@ const ComparisonResult = () => {
|
||||
|
||||
<div className="cycle-time-container comparisionCard">
|
||||
<div className="cycle-main">
|
||||
<div className="cycle-header">Cycle Time</div>
|
||||
<h4 className="cycle-header">Cycle Time</h4>
|
||||
<div className="layers-wrapper">
|
||||
<div className="layers">
|
||||
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||
@@ -202,7 +202,7 @@ const ComparisonResult = () => {
|
||||
</div>
|
||||
{/*
|
||||
<div className="overallDowntime-container comparisionCard">
|
||||
<div className="overallDowntime-header">Overall Downtime</div>
|
||||
<h4 className="overallDowntime-header">Overall Downtime</h4>
|
||||
<div className="totalDownTime-wrapper">
|
||||
<div className="totalDownTime">
|
||||
<div className="totalDownTime-right">
|
||||
@@ -221,7 +221,7 @@ const ComparisonResult = () => {
|
||||
</div> */}
|
||||
|
||||
<div className="overallScrapRate comparisionCard">
|
||||
<div className="overallScrapRate-header">Production Capacity</div>
|
||||
<h4 className="overallScrapRate-header">Production Capacity</h4>
|
||||
<div className="overallScrapRate-wrapper">
|
||||
<div className="overallScrapRate-value">
|
||||
<div className="overallScrapRate-label">{highestProductivityProduct?.productName}</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ ChartJS.register(
|
||||
Legend
|
||||
);
|
||||
|
||||
const EnergyUsage = () => {
|
||||
const EnergyUsage = ({comparedProducts}:any) => {
|
||||
const data = useMemo(() => {
|
||||
const randomizeData = () =>
|
||||
Array.from({ length: 5 }, () => Math.floor(Math.random() * (2000 - 300 + 1)) + 300);
|
||||
@@ -90,14 +90,14 @@ const EnergyUsage = () => {
|
||||
<div className="simulation-wrapper sim-1">
|
||||
<div className="icon"></div>
|
||||
<div className="simulation-details-wrapper">
|
||||
<div className="label">Simulation 1</div>
|
||||
<div className="label">{comparedProducts[0]?.productName}</div>
|
||||
<div className="value">98%</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="simulation-wrapper sim-2">
|
||||
<div className="icon"></div>
|
||||
<div className="simulation-details-wrapper">
|
||||
<div className="label">Simulation 2</div>
|
||||
<div className="label">{comparedProducts[1]?.productName}</div>
|
||||
<div className="value">97%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ const PerformanceResult = ({ comparedProducts }: any) => {
|
||||
<div className="icon">
|
||||
<PerformanceIcon />
|
||||
</div>
|
||||
<div className="head">Performance result</div>
|
||||
<h4 className="head">Performance result</h4>
|
||||
</div>
|
||||
|
||||
<div className="metrics-container">
|
||||
@@ -56,7 +56,7 @@ const PerformanceResult = ({ comparedProducts }: any) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="simulation-tag">Simulation 1</div>
|
||||
<div className="simulation-tag">{ProfitProduct.productName}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import List from "./List";
|
||||
import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
|
||||
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
|
||||
import { useZones } from "../../../store/builder/store";
|
||||
import { useAssetsStore } from "../../../store/builder/useAssetStore";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
|
||||
interface DropDownListProps {
|
||||
value?: string; // Value to display in the DropDownList
|
||||
@@ -51,8 +51,9 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||
};
|
||||
|
||||
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
|
||||
const { assets } = useAssetsStore();
|
||||
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets } = assetStore();
|
||||
|
||||
const isPointInsidePolygon = (
|
||||
point: [number, number],
|
||||
polygon: [number, number][]
|
||||
@@ -129,7 +130,7 @@ const DropDownList: React.FC<DropDownListProps> = ({
|
||||
title="collapse-btn"
|
||||
className="collapse-icon option"
|
||||
style={{ transform: isOpen ? "rotate(0deg)" : "rotate(-90deg)" }}
|
||||
// onClick={handleToggle}
|
||||
// onClick={handleToggle}
|
||||
>
|
||||
<ArrowIcon />
|
||||
</button>
|
||||
|
||||
@@ -17,9 +17,10 @@ import {
|
||||
useZones,
|
||||
} from "../../../store/builder/store";
|
||||
import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
|
||||
import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useAssetsStore } from "../../../store/builder/useAssetStore";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
|
||||
interface Asset {
|
||||
id: string;
|
||||
@@ -46,12 +47,11 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||
const { zones, setZones } = useZones();
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>({});
|
||||
const { projectId } = useParams();
|
||||
|
||||
const { setName } = useAssetsStore();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { setName } = assetStore();
|
||||
const { organization } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
useSelectedZoneStore.getState().setSelectedZone({
|
||||
@@ -81,9 +81,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
|
||||
setSubModule("zoneProperties");
|
||||
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email?.split("@")[1]?.split(".")[0] ?? "";
|
||||
|
||||
let response = await getZoneData(id, organization, projectId);
|
||||
setSelectedZone({
|
||||
zoneName: response?.zoneName,
|
||||
@@ -100,14 +97,12 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleAssetClick(asset: Asset) {
|
||||
setZoneAssetId(asset);
|
||||
}
|
||||
|
||||
async function handleZoneNameChange(newName: string) {
|
||||
const email = localStorage.getItem("email") ?? "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
const isDuplicate = zones.some(
|
||||
(zone: any) =>
|
||||
zone.zoneName?.trim().toLowerCase() === newName?.trim().toLowerCase() &&
|
||||
@@ -136,18 +131,14 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
}
|
||||
|
||||
async function handleZoneAssetName(newName: string) {
|
||||
const email = localStorage.getItem("email") ?? "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
if (zoneAssetId?.id) {
|
||||
let response = await setFloorItemApi(
|
||||
organization,
|
||||
zoneAssetId.id,
|
||||
newName,
|
||||
let response = await setAssetsApi({
|
||||
modelUuid: zoneAssetId.id,
|
||||
modelName: newName,
|
||||
projectId
|
||||
);
|
||||
});
|
||||
// console.log("response: ", response);
|
||||
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
|
||||
|
||||
setName(zoneAssetId.id, response.modelName);
|
||||
}
|
||||
@@ -207,20 +198,23 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
id: '',
|
||||
name: '',
|
||||
});
|
||||
setSubModule("properties")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', onMouseDown);
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
if (selectedZone.zoneName! === '' && activeModule === 'Builder') {
|
||||
document.addEventListener('mousedown', onMouseDown);
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', onMouseDown);
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
};
|
||||
}, []);
|
||||
}, [selectedZone, activeModule]);
|
||||
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,12 +2,11 @@ import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||
import { toggleTheme } from "../../../utils/theme";
|
||||
import useVersionHistoryStore, {
|
||||
import useVersionHistoryVisibleStore, {
|
||||
useShortcutStore,
|
||||
useVersionStore,
|
||||
} from "../../../store/builder/store";
|
||||
import { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
||||
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||
|
||||
interface MenuBarProps {
|
||||
setOpenMenu: (isOpen: boolean) => void;
|
||||
@@ -22,16 +21,15 @@ interface MenuItem {
|
||||
}
|
||||
|
||||
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
||||
|
||||
const navigate = useNavigate();
|
||||
const [activeMenu, setActiveMenu] = useState<string | null>(null);
|
||||
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
|
||||
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>({});
|
||||
|
||||
const { setVersionHistory } = useVersionHistoryStore();
|
||||
const { setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { setActiveModule } = useModuleStore();
|
||||
const { setSubModule } = useSubModuleStore();
|
||||
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
||||
|
||||
@@ -59,35 +57,21 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
setShowShortcuts(!showShortcuts);
|
||||
}
|
||||
|
||||
function handleVersionCreation() {
|
||||
setCreateNewVersion(true);
|
||||
setVersionHistoryVisible(true);
|
||||
setSubModule("properties");
|
||||
setActiveModule('builder');
|
||||
}
|
||||
|
||||
const menus: Record<string, MenuItem[]> = {
|
||||
File: [
|
||||
{ label: "New File", shortcut: "Ctrl + N" },
|
||||
{ label: "Open Local File", shortcut: "Ctrl + O" },
|
||||
{
|
||||
label: "Save Version",
|
||||
action: () => {
|
||||
const versionStore = useVersionStore.getState();
|
||||
const versionCount = versionStore.versions.length;
|
||||
|
||||
const newVersion = {
|
||||
id: generateUniqueId(),
|
||||
versionLabel: `v${versionCount + 1}.0`,
|
||||
timestamp: `${new Date().toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
})} ${new Date().toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
})}`,
|
||||
|
||||
savedBy: userName,
|
||||
};
|
||||
|
||||
console.log("newVersion: ", newVersion);
|
||||
versionStore.addVersion(newVersion);
|
||||
},
|
||||
shortcut: "Ctrl + Alt + S",
|
||||
action: handleVersionCreation,
|
||||
},
|
||||
{ label: "Make a Copy" },
|
||||
{ label: "Share" },
|
||||
@@ -236,11 +220,14 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
setActiveSubMenu(null);
|
||||
}}
|
||||
onClick={() => {
|
||||
setVersionHistory(true);
|
||||
setVersionHistoryVisible(true);
|
||||
setSubModule("properties");
|
||||
setActiveModule('builder');
|
||||
}}
|
||||
>
|
||||
<div className="menu-button">Version history</div>
|
||||
<div className="menu-button">
|
||||
Version history <div className="value">Ctrl + H</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Theme */}
|
||||
|
||||
@@ -13,6 +13,7 @@ interface AssetDetailsCardInterface {
|
||||
enableStatue?: boolean;
|
||||
count?: number;
|
||||
totalCapacity?: number;
|
||||
activeTime?: any;
|
||||
assetDetails?: {
|
||||
assetName: string;
|
||||
const: string;
|
||||
@@ -59,6 +60,7 @@ const AssetDetailsCard: React.FC<AssetDetailsCardInterface> = ({
|
||||
status,
|
||||
count,
|
||||
totalCapacity,
|
||||
activeTime,
|
||||
assetDetails,
|
||||
}) => {
|
||||
const [moreDetails, setMoreDetails] = useState(false);
|
||||
@@ -75,7 +77,10 @@ const AssetDetailsCard: React.FC<AssetDetailsCardInterface> = ({
|
||||
<div className="content">
|
||||
<div className="name">{name}</div>
|
||||
{enableStatue && (
|
||||
<div className="status-container">{GetStatus(status)}</div>
|
||||
<>
|
||||
<div className="active-time">Active Time : <span className="value">{activeTime}</span></div>
|
||||
<div className="status-container">{GetStatus(status)}</div>
|
||||
</>
|
||||
)}
|
||||
{!enableStatue && totalCapacity && (
|
||||
<div className="storage-container">Storage/Inventory</div>
|
||||
|
||||
@@ -167,7 +167,7 @@ const SimulationPlayer: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
{isPlaying && activeModule === "simulation" && (
|
||||
<div className="label-toogler">
|
||||
<div className="label-toogler "> {/* bottom */}
|
||||
<InputToggle
|
||||
value={viewSceneLabels}
|
||||
inputKey="1"
|
||||
@@ -187,7 +187,7 @@ const SimulationPlayer: React.FC = () => {
|
||||
<div className="icon">
|
||||
<HourlySimulationIcon />
|
||||
</div>
|
||||
<div className="label">ThroughPut</div>
|
||||
<h4 className="label">ThroughPut</h4>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
|
||||
@@ -1,103 +1,110 @@
|
||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import * as THREE from 'three';
|
||||
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getWallItems } from '../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi';
|
||||
import { retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||
import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
async function loadInitialWallItems(
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
projectId?: string
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
const email = localStorage.getItem('email');
|
||||
if (!email) {
|
||||
throw new Error('No email found in localStorage');
|
||||
}
|
||||
if (!projectId || !versionId) return;
|
||||
try {
|
||||
const { organization, email } = getUserData();
|
||||
|
||||
const organization = email.split("@")[1].split(".")[0];
|
||||
const items = await getWallItems(organization, projectId);
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
if (!items || items.length === 0) {
|
||||
localStorage.removeItem("WallItems");
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
const loadedWallItems = await Promise.all(items.map(async (item: Types.WallItem) => {
|
||||
// Check THREE.js cache first
|
||||
const cachedModel = THREE.Cache.get(item.assetId!);
|
||||
if (cachedModel) {
|
||||
return processModel(cachedModel, item);
|
||||
}
|
||||
|
||||
// Check IndexedDB cache
|
||||
const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Load from original URL if not cached
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(modelUrl, async (gltf) => {
|
||||
try {
|
||||
// Cache the model
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.assetId!, modelBlob);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
} catch (error) {
|
||||
console.error('Failed to cache model:', error);
|
||||
resolve(processModel(gltf, item));
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
setWallItems(loadedWallItems);
|
||||
} catch (error) {
|
||||
console.error('Failed to load wall items:', error);
|
||||
if (!email) {
|
||||
throw new Error("No email found in localStorage");
|
||||
}
|
||||
|
||||
const items = await getWallItems(organization, projectId, versionId);
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
if (!items || items.length === 0) {
|
||||
localStorage.removeItem("WallItems");
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
const loadedWallItems = await Promise.all(
|
||||
items.map(async (item: Types.WallItem) => {
|
||||
// Check THREE.js cache first
|
||||
const cachedModel = THREE.Cache.get(item.assetId!);
|
||||
if (cachedModel) {
|
||||
return processModel(cachedModel, item);
|
||||
}
|
||||
|
||||
// Check IndexedDB cache
|
||||
const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Load from original URL if not cached
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(modelUrl, async (gltf) => {
|
||||
try {
|
||||
// Cache the model
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.assetId!, modelBlob);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
} catch (error) {
|
||||
console.error("Failed to cache model:", error);
|
||||
resolve(processModel(gltf, item));
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
setWallItems(loadedWallItems);
|
||||
} catch (error) {
|
||||
console.error("Failed to load wall items:", error);
|
||||
}
|
||||
}
|
||||
|
||||
function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
||||
const model = gltf.scene.clone();
|
||||
model.uuid = item.modelUuid!;
|
||||
const model = gltf.scene.clone();
|
||||
model.uuid = item.modelUuid!;
|
||||
|
||||
model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
type: item.type,
|
||||
model: model,
|
||||
modelName: item.modelName,
|
||||
assetId: item.assetId,
|
||||
scale: item.scale,
|
||||
csgscale: item.csgscale,
|
||||
csgposition: item.csgposition,
|
||||
position: item.position,
|
||||
quaternion: item.quaternion,
|
||||
};
|
||||
return {
|
||||
type: item.type,
|
||||
model: model,
|
||||
modelName: item.modelName,
|
||||
assetId: item.assetId,
|
||||
scale: item.scale,
|
||||
csgscale: item.csgscale,
|
||||
csgposition: item.csgposition,
|
||||
position: item.position,
|
||||
quaternion: item.quaternion,
|
||||
};
|
||||
}
|
||||
|
||||
export default loadInitialWallItems;
|
||||
export default loadInitialWallItems;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
import { useToggleView } from '../../../../store/builder/store';
|
||||
import AisleInstance from './instance/aisleInstance';
|
||||
import Point from '../../point/point';
|
||||
import { Html } from '@react-three/drei';
|
||||
import { Vector3 } from 'three';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
function AisleInstances() {
|
||||
const { aisles } = useAisleStore();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { aisles } = aisleStore();
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
const allPoints = useMemo(() => {
|
||||
@@ -26,8 +27,6 @@ function AisleInstances() {
|
||||
return points;
|
||||
}, [aisles]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView &&
|
||||
|
||||
@@ -2,12 +2,13 @@ import * as THREE from 'three'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
import ReferenceAisle from './referenceAisle';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import { createAisleApi } from '../../../../services/factoryBuilder/aisle/createAisleApi';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useVersionContext } from '../../version/versionContext';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
function AisleCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -16,14 +17,17 @@ function AisleCreator() {
|
||||
const { toolMode } = useToolMode();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { socket } = useSocketStore();
|
||||
const { addAisle, getAislePointById } = useAisleStore();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { addAisle, getAislePointById } = aisleStore();
|
||||
const drag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, snappedPosition, snappedPoint } = useBuilderStore();
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, snappedPosition, snappedPoint, setSnappedPosition, setSnappedPoint } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
@@ -100,7 +104,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -123,7 +127,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -145,7 +149,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -166,7 +170,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -189,7 +193,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -211,7 +215,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -232,7 +236,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -254,7 +258,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId)
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -270,6 +274,10 @@ function AisleCreator() {
|
||||
};
|
||||
|
||||
if (toolMode === "Aisle" && toggleView) {
|
||||
if (tempPoints.length === 0) {
|
||||
setSnappedPosition(null);
|
||||
setSnappedPoint(null);
|
||||
}
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
@@ -294,7 +302,7 @@ function AisleCreator() {
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContext);
|
||||
};
|
||||
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, getAislePointById, aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, snappedPosition, snappedPoint]);
|
||||
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addAisle, getAislePointById, aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, snappedPosition, snappedPoint, selectedVersion?.versionId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -25,7 +25,7 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
||||
const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);
|
||||
|
||||
const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[0]?.position || null);
|
||||
const { checkSnapForAisle } = usePointSnapping({ uuid: 'temp-aisle', pointType: 'Aisle', position: directionalSnap.position || [0, 0, 0] });
|
||||
const { snapAislePoint } = usePointSnapping({ uuid: 'temp-aisle', pointType: 'Aisle', position: directionalSnap.position || [0, 0, 0] });
|
||||
|
||||
useFrame(() => {
|
||||
if (toolMode === "Aisle" && toggleView && tempPoints.length === 1) {
|
||||
@@ -36,7 +36,7 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
||||
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
|
||||
if (intersectionPoint) {
|
||||
const snapped = checkSnapForAisle([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
const snapped = snapAislePoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
|
||||
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||
finalPosition.current = snapped.position;
|
||||
|
||||
@@ -3,20 +3,29 @@ import AisleCreator from './aisleCreator/aisleCreator'
|
||||
import AisleInstances from './Instances/aisleInstances'
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getAisleApi } from '../../../services/factoryBuilder/aisle/getAisleApi';
|
||||
import { useAisleStore } from '../../../store/builder/useAisleStore';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
|
||||
function AislesGroup() {
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { setAisles } = aisleStore();
|
||||
const { projectId } = useParams();
|
||||
const { setAisles } = useAisleStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAisle = async () => {
|
||||
if (projectId) {
|
||||
const aisles = await getAisleApi(projectId);
|
||||
setAisles(aisles);
|
||||
}
|
||||
if (projectId) {
|
||||
getAisleApi(projectId, selectedVersion?.versionId || '').then((aisles) => {
|
||||
if (aisles && aisles.length > 0) {
|
||||
setAisles(aisles);
|
||||
} else {
|
||||
setAisles([]);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
fetchAisle()
|
||||
}, [])
|
||||
}, [projectId, selectedVersion?.versionId])
|
||||
|
||||
return (
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelect
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import { FloorItems, RefGroup, RefMesh } from "../../../types/world/worldTypes";
|
||||
import { useAssetsStore } from "../../../store/builder/useAssetStore";
|
||||
import { useEventsStore } from "../../../store/simulation/useEventsStore";
|
||||
import Models from "./models/models";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
@@ -14,6 +12,9 @@ import { CameraControls } from "@react-three/drei";
|
||||
import addAssetModel from "./functions/addAssetModel";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../scene/sceneContext";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
|
||||
const gltfLoaderWorker = new Worker(
|
||||
new URL(
|
||||
@@ -27,15 +28,16 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
const { socket } = useSocketStore();
|
||||
const { controls, gl, pointer, camera, raycaster } = useThree();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { setAssets, addAsset } = useAssetsStore();
|
||||
const { addEvent } = useEventsStore();
|
||||
const { assetStore, eventStore } = useSceneContext();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { setAssets, addAsset, clearAssets } = assetStore();
|
||||
const { addEvent, clearEvents } = eventStore();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { projectId } = useParams();
|
||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
const userId = localStorage.getItem("userId")!;
|
||||
const { userId, organization } = getUserData();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
|
||||
@@ -48,6 +50,8 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
useEffect(() => {
|
||||
if (!projectId || !selectedVersion) return;
|
||||
clearEvents();
|
||||
|
||||
let totalAssets = 0;
|
||||
let loadedAssets = 0;
|
||||
@@ -65,8 +69,8 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
}
|
||||
};
|
||||
|
||||
getFloorAssets(organization, projectId).then((data) => {
|
||||
if (data.length > 0) {
|
||||
getFloorAssets(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
if (data && data.length > 0) {
|
||||
const uniqueItems = (data as FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.assetId === item.assetId));
|
||||
totalAssets = uniqueItems.length;
|
||||
if (totalAssets === 0) {
|
||||
@@ -77,8 +81,11 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
} else {
|
||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||
updateLoadingProgress(100);
|
||||
clearAssets();
|
||||
}
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
})
|
||||
|
||||
gltfLoaderWorker.onmessage = async (event) => {
|
||||
if (event.data.message === "gltfLoaded" && event.data.modelBlob) {
|
||||
@@ -94,7 +101,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
|
||||
if (loadedAssets === totalAssets) {
|
||||
const assets: Asset[] = [];
|
||||
getFloorAssets(organization, projectId).then((data: FloorItems) => {
|
||||
getFloorAssets(organization, projectId, selectedVersion.versionId || '').then((data: FloorItems) => {
|
||||
data.forEach((item) => {
|
||||
if (item.eventData) {
|
||||
assets.push({
|
||||
@@ -257,7 +264,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
});
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
}, [selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
@@ -270,13 +277,14 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, projectId, userId);
|
||||
addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
||||
}
|
||||
};
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const onMouseMove = (evt: any) => {
|
||||
if (!canvasElement) return;
|
||||
const canvasRect = canvasElement.getBoundingClientRect();
|
||||
@@ -286,14 +294,11 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
setTop(relativeY);
|
||||
setLeft(relativeX);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
const onMouseUp = (evt: any) => {
|
||||
setIsRenameMode(false);
|
||||
}
|
||||
|
||||
|
||||
if (activeModule === "builder") {
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
|
||||
@@ -3,425 +3,496 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function addAssetModel(
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
floorGroup: Types.RefGroup,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
plane: Types.RefMesh,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
floorGroup: Types.RefGroup,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
plane: Types.RefMesh,
|
||||
selectedVersion?: Version | null,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
): Promise<void> {
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
try {
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
try {
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor"));
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const floorIntersections = raycaster.intersectObjects(
|
||||
floorGroup.current.children,
|
||||
true
|
||||
);
|
||||
const intersectedFloor = floorIntersections.find((intersect) =>
|
||||
intersect.object.name.includes("Floor")
|
||||
);
|
||||
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
intersectPoint =
|
||||
intersectedFloor.distance < intersectedPlane.distance
|
||||
? new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)
|
||||
: new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId);
|
||||
});
|
||||
} else {
|
||||
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to add asset");
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
intersectPoint =
|
||||
intersectedFloor.distance < intersectedPlane.distance
|
||||
? new THREE.Vector3(
|
||||
intersectedFloor.point.x,
|
||||
Math.round(intersectedFloor.point.y),
|
||||
intersectedFloor.point.z
|
||||
)
|
||||
: new THREE.Vector3(
|
||||
intersectedPlane.point.x,
|
||||
0,
|
||||
intersectedPlane.point.z
|
||||
);
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectedFloor.point.x,
|
||||
Math.round(intersectedFloor.point.y),
|
||||
intersectedFloor.point.z
|
||||
);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectedPlane.point.x,
|
||||
0,
|
||||
intersectedPlane.point.z
|
||||
);
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectPoint.x,
|
||||
0,
|
||||
intersectPoint.z
|
||||
);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(
|
||||
cachedModel,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(
|
||||
gltf,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
});
|
||||
} else {
|
||||
loader.load(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`
|
||||
).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(
|
||||
gltf,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to add asset");
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleModelLoad(
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
socket: Socket<any>,
|
||||
versionId: string,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
) {
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = {
|
||||
name: selectedItem.name,
|
||||
modelId: selectedItem.id,
|
||||
modelUuid: model.uuid,
|
||||
};
|
||||
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
||||
const { organization } = getUserData();
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = {
|
||||
name: selectedItem.name,
|
||||
modelId: selectedItem.id,
|
||||
modelUuid: model.uuid,
|
||||
};
|
||||
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const newFloorItem: Asset = {
|
||||
modelUuid: model.uuid,
|
||||
modelName: selectedItem.name,
|
||||
assetId: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: [0, 0, 0],
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
isCollidable: false,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email ? email.split("@")[1].split(".")[0] : "";
|
||||
|
||||
// API
|
||||
|
||||
// await setFloorItemApi(
|
||||
// organization,
|
||||
// newFloorItem.modelUuid,
|
||||
// newFloorItem.modelName,
|
||||
// newFloorItem.assetId,
|
||||
// newFloorItem.position,
|
||||
// { x: 0, y: 0, z: 0 },
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
if (selectedItem.type) {
|
||||
const data = PointsCalculator(
|
||||
selectedItem.type,
|
||||
gltf.scene.clone(),
|
||||
new THREE.Vector3(...model.rotation)
|
||||
);
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = {
|
||||
type: selectedItem.type,
|
||||
};
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
speed: 1,
|
||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||
const triggers: TriggerSchema[] = [];
|
||||
|
||||
if (data.points && index < data.points.length - 1) {
|
||||
triggers.push({
|
||||
triggerUuid: THREE.MathUtils.generateUUID(),
|
||||
triggerName: `Trigger 1`,
|
||||
triggerType: "onComplete",
|
||||
delay: 0,
|
||||
triggeredAsset: {
|
||||
triggeredModel: {
|
||||
modelName: newFloorItem.modelName,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
},
|
||||
triggeredPoint: {
|
||||
pointName: `Point`,
|
||||
pointUuid: "",
|
||||
},
|
||||
triggeredAction: {
|
||||
actionName: `Action 1`,
|
||||
actionUuid: "",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [point.x, point.y, point.z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: "default",
|
||||
material: "Default Material",
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: triggers,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
||||
const currentPoint = ConveyorEvent.points[i];
|
||||
const nextPoint = ConveyorEvent.points[i + 1];
|
||||
|
||||
if (currentPoint.action.triggers.length > 0) {
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid;
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid;
|
||||
}
|
||||
}
|
||||
addEvent(ConveyorEvent);
|
||||
eventData.points = ConveyorEvent.points.map((point) => ({
|
||||
uuid: point.uuid,
|
||||
position: point.position,
|
||||
rotation: point.rotation,
|
||||
}));
|
||||
} else if (selectedItem.type === "Vehicle") {
|
||||
const vehicleEvent: VehicleEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "travel",
|
||||
unLoadDuration: 5,
|
||||
loadCapacity: 1,
|
||||
steeringAngle: 0,
|
||||
pickUpPoint: null,
|
||||
unLoadPoint: null,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(vehicleEvent);
|
||||
eventData.point = {
|
||||
uuid: vehicleEvent.point.uuid,
|
||||
position: vehicleEvent.point.position,
|
||||
rotation: vehicleEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "ArmBot") {
|
||||
const roboticArmEvent: RoboticArmEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
addEvent(roboticArmEvent);
|
||||
eventData.point = {
|
||||
uuid: roboticArmEvent.point.uuid,
|
||||
position: roboticArmEvent.point.position,
|
||||
rotation: roboticArmEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "StaticMachine") {
|
||||
const machineEvent: MachineEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "process",
|
||||
processTime: 10,
|
||||
swapMaterial: "Default Material",
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(machineEvent);
|
||||
eventData.point = {
|
||||
uuid: machineEvent.point.uuid,
|
||||
position: machineEvent.point.position,
|
||||
rotation: machineEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "Storage") {
|
||||
const storageEvent: StorageEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "store",
|
||||
storageCapacity: 10,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
eventData.point = {
|
||||
uuid: storageEvent.point.uuid,
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation,
|
||||
};
|
||||
}
|
||||
|
||||
const completeData = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
eventData: eventData,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
|
||||
const asset: Asset = {
|
||||
modelUuid: completeData.modelUuid,
|
||||
modelName: completeData.modelName,
|
||||
assetId: completeData.assetId,
|
||||
position: completeData.position,
|
||||
rotation: [
|
||||
completeData.rotation.x,
|
||||
completeData.rotation.y,
|
||||
completeData.rotation.z,
|
||||
] as [number, number, number],
|
||||
isLocked: completeData.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: completeData.isVisible,
|
||||
opacity: 1,
|
||||
eventData: completeData.eventData,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
} else {
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
|
||||
const asset = {
|
||||
modelUuid: data.modelUuid,
|
||||
modelName: data.modelName,
|
||||
assetId: data.assetId,
|
||||
position: data.position,
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [number, number, number],
|
||||
isLocked: data.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: data.isVisible,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const newFloorItem: Asset = {
|
||||
modelUuid: model.uuid,
|
||||
modelName: selectedItem.name,
|
||||
assetId: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: [0, 0, 0],
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
isCollidable: false,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
|
||||
// API
|
||||
|
||||
// await setAssetsApi(
|
||||
// organization,
|
||||
// newFloorItem.modelUuid,
|
||||
// newFloorItem.modelName,
|
||||
// newFloorItem.assetId,
|
||||
// newFloorItem.position,
|
||||
// { x: 0, y: 0, z: 0 },
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
if (selectedItem.type) {
|
||||
const data = PointsCalculator(
|
||||
selectedItem.type,
|
||||
gltf.scene.clone(),
|
||||
new THREE.Vector3(...model.rotation)
|
||||
);
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = {
|
||||
type: selectedItem.type,
|
||||
};
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
speed: 1,
|
||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||
const triggers: TriggerSchema[] = [];
|
||||
|
||||
if (data.points && index < data.points.length - 1) {
|
||||
triggers.push({
|
||||
triggerUuid: THREE.MathUtils.generateUUID(),
|
||||
triggerName: `Trigger 1`,
|
||||
triggerType: "onComplete",
|
||||
delay: 0,
|
||||
triggeredAsset: {
|
||||
triggeredModel: {
|
||||
modelName: newFloorItem.modelName,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
},
|
||||
triggeredPoint: {
|
||||
pointName: `Point`,
|
||||
pointUuid: "",
|
||||
},
|
||||
triggeredAction: {
|
||||
actionName: `Action 1`,
|
||||
actionUuid: "",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [point.x, point.y, point.z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: "default",
|
||||
material: "Default Material",
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: triggers,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
||||
const currentPoint = ConveyorEvent.points[i];
|
||||
const nextPoint = ConveyorEvent.points[i + 1];
|
||||
|
||||
if (currentPoint.action.triggers.length > 0) {
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid =
|
||||
nextPoint.uuid;
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid =
|
||||
nextPoint.action.actionUuid;
|
||||
}
|
||||
}
|
||||
addEvent(ConveyorEvent);
|
||||
eventData.points = ConveyorEvent.points.map((point) => ({
|
||||
uuid: point.uuid,
|
||||
position: point.position,
|
||||
rotation: point.rotation,
|
||||
}));
|
||||
} else if (selectedItem.type === "Vehicle") {
|
||||
const vehicleEvent: VehicleEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "travel",
|
||||
unLoadDuration: 5,
|
||||
loadCapacity: 1,
|
||||
steeringAngle: 0,
|
||||
pickUpPoint: null,
|
||||
unLoadPoint: null,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(vehicleEvent);
|
||||
eventData.point = {
|
||||
uuid: vehicleEvent.point.uuid,
|
||||
position: vehicleEvent.point.position,
|
||||
rotation: vehicleEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "ArmBot") {
|
||||
const roboticArmEvent: RoboticArmEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
addEvent(roboticArmEvent);
|
||||
eventData.point = {
|
||||
uuid: roboticArmEvent.point.uuid,
|
||||
position: roboticArmEvent.point.position,
|
||||
rotation: roboticArmEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "StaticMachine") {
|
||||
const machineEvent: MachineEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "process",
|
||||
processTime: 10,
|
||||
swapMaterial: "Default Material",
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(machineEvent);
|
||||
eventData.point = {
|
||||
uuid: machineEvent.point.uuid,
|
||||
position: machineEvent.point.position,
|
||||
rotation: machineEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "Storage") {
|
||||
const storageEvent: StorageEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "store",
|
||||
storageCapacity: 10,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
eventData.point = {
|
||||
uuid: storageEvent.point.uuid,
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation,
|
||||
};
|
||||
}
|
||||
|
||||
const completeData = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
eventData: eventData,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
|
||||
const asset: Asset = {
|
||||
modelUuid: completeData.modelUuid,
|
||||
modelName: completeData.modelName,
|
||||
assetId: completeData.assetId,
|
||||
position: completeData.position,
|
||||
rotation: [
|
||||
completeData.rotation.x,
|
||||
completeData.rotation.y,
|
||||
completeData.rotation.z,
|
||||
] as [number, number, number],
|
||||
isLocked: completeData.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: completeData.isVisible,
|
||||
opacity: 1,
|
||||
eventData: completeData.eventData,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
} else {
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
|
||||
const asset = {
|
||||
modelUuid: data.modelUuid,
|
||||
modelName: data.modelName,
|
||||
assetId: data.assetId,
|
||||
position: data.position,
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
],
|
||||
isLocked: data.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: data.isVisible,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
export default addAssetModel;
|
||||
|
||||
@@ -7,14 +7,14 @@ import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||
import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { useAssetsStore } from '../../../../../store/builder/useAssetStore';
|
||||
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||
import { useProductContext } from '../../../../simulation/products/productContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../functions/getUserData';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../../version/versionContext';
|
||||
|
||||
function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { camera, controls, gl } = useThree();
|
||||
@@ -22,11 +22,12 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { toggleView } = useToggleView();
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { removeAsset } = useAssetsStore();
|
||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||
const { removeAsset } = assetStore();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
const { getIsEventInProduct } = useProductStore();
|
||||
const { getEventByModelUuid } = useEventsStore();
|
||||
const { getIsEventInProduct } = productStore();
|
||||
const { getEventByModelUuid } = eventStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
@@ -40,7 +41,10 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
@@ -162,9 +166,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
|
||||
const handleClick = (asset: Asset) => {
|
||||
if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
|
||||
//REST
|
||||
|
||||
@@ -173,18 +175,19 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
modelName: asset.modelName,
|
||||
socketId: socket.id,
|
||||
userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId
|
||||
}
|
||||
|
||||
const response = socket.emit('v1:model-asset:delete', data)
|
||||
|
||||
useEventsStore.getState().removeEvent(asset.modelUuid);
|
||||
useProductStore.getState().deleteEvent(asset.modelUuid);
|
||||
eventStore.getState().removeEvent(asset.modelUuid);
|
||||
productStore.getState().deleteEvent(asset.modelUuid);
|
||||
|
||||
if (response) {
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { useAssetsStore } from '../../../../store/builder/useAssetStore';
|
||||
import Model from './model/model';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { Vector3 } from 'three';
|
||||
import { useSelectedFloorItem } from '../../../../store/builder/store';
|
||||
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
function Models() {
|
||||
const { controls } = useThree();
|
||||
const { assets } = useAssetsStore();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets } = assetStore();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import { useParams } from "react-router-dom";
|
||||
import AislesGroup from "./aisle/aislesGroup";
|
||||
import WallGroup from "./wall/wallGroup";
|
||||
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
|
||||
export default function Builder() {
|
||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||
@@ -104,6 +105,7 @@ export default function Builder() {
|
||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
||||
const { projectId } = useParams();
|
||||
const { setHoveredPoint } = useBuilderStore();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
// const loader = new GLTFLoader();
|
||||
// const dracoLoader = new DRACOLoader();
|
||||
@@ -134,11 +136,9 @@ export default function Builder() {
|
||||
}, [toggleView]);
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
async function fetchVisibility() {
|
||||
const data = await findEnvironment(organization, localStorage.getItem("userId")!, projectId);
|
||||
const data = await findEnvironment(organization, userId, projectId);
|
||||
if (data) {
|
||||
setRoofVisibility(data.roofVisibility);
|
||||
setWallVisibility(data.wallVisibility);
|
||||
@@ -255,8 +255,6 @@ export default function Builder() {
|
||||
plane={plane}
|
||||
/>
|
||||
|
||||
{/* <WallGroup /> */}
|
||||
|
||||
<AislesGroup />
|
||||
|
||||
<MeasurementTool />
|
||||
@@ -275,6 +273,8 @@ export default function Builder() {
|
||||
|
||||
<LayoutImage />
|
||||
</Bvh>
|
||||
|
||||
{/* <WallGroup /> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBluepri
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
|
||||
// Interface defining the props for the DxfFile component
|
||||
interface DxfFileProps {
|
||||
@@ -35,7 +37,10 @@ const DxfFile = ({
|
||||
const { setUpdateScene } = useUpdateScene();
|
||||
const { toggleView } = useToggleView();
|
||||
const { socket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
// Refs for storing line objects
|
||||
const lineRefs = useRef<Line[]>([]);
|
||||
@@ -56,9 +61,6 @@ const DxfFile = ({
|
||||
lines.current.push(...dfxWallGenerate);
|
||||
dfxWallGenerate.map((line: any) => {
|
||||
const lineData = arrayLineToObject(line as Types.Line);
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
@@ -67,11 +69,12 @@ const DxfFile = ({
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
organization,
|
||||
layer: lineData.layer,
|
||||
line: lineData.line,
|
||||
type: lineData.type,
|
||||
socketId: socket.id,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
|
||||
@@ -1,84 +1,100 @@
|
||||
import * as THREE from 'three';
|
||||
import { DragControls } from 'three/examples/jsm/controls/DragControls';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import DragPoint from '../geomentries/points/dragPoint';
|
||||
import * as THREE from "three";
|
||||
import { DragControls } from "three/examples/jsm/controls/DragControls";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import DragPoint from "../geomentries/points/dragPoint";
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
export default async function addDragControl(
|
||||
dragPointControls: Types.RefDragControl,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
state: Types.ThreeState,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
socket: Socket<any>,
|
||||
projectId?:string
|
||||
dragPointControls: Types.RefDragControl,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
state: Types.ThreeState,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
) {
|
||||
////////// Dragging Point and also change the size to indicate during hover //////////
|
||||
|
||||
////////// Dragging Point and also change the size to indicate during hover //////////
|
||||
dragPointControls.current = new DragControls(
|
||||
currentLayerPoint.current,
|
||||
state.camera,
|
||||
state.gl.domElement
|
||||
);
|
||||
dragPointControls.current.enabled = false;
|
||||
const { userId, organization, email } = getUserData();
|
||||
dragPointControls.current.addEventListener("drag", function (event) {
|
||||
const object = event.object;
|
||||
if (object.visible) {
|
||||
(state.controls as any).enabled = false;
|
||||
DragPoint(
|
||||
event as any,
|
||||
floorPlanGroupPoint,
|
||||
floorPlanGroupLine,
|
||||
state.scene,
|
||||
lines,
|
||||
onlyFloorlines
|
||||
);
|
||||
} else {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current = new DragControls(currentLayerPoint.current, state.camera, state.gl.domElement);
|
||||
dragPointControls.current.enabled = false;
|
||||
dragPointControls.current.addEventListener("dragstart", function (event) { });
|
||||
|
||||
dragPointControls.current.addEventListener('drag', function (event) {
|
||||
const object = event.object;
|
||||
if (object.visible) {
|
||||
(state.controls as any).enabled = false;
|
||||
DragPoint(event as any, floorPlanGroupPoint, floorPlanGroupLine, state.scene, lines, onlyFloorlines)
|
||||
} else {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
dragPointControls.current.addEventListener("dragend", async function (event) {
|
||||
if (!dragPointControls.current) return;
|
||||
|
||||
dragPointControls.current.addEventListener('dragstart', function (event) {
|
||||
});
|
||||
//REST
|
||||
|
||||
dragPointControls.current.addEventListener('dragend', async function (event) {
|
||||
if (!dragPointControls.current) return;
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
// await updatePoint(
|
||||
// organization,
|
||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
// event.object.uuid,
|
||||
// )
|
||||
|
||||
//REST
|
||||
//SOCKET
|
||||
|
||||
// await updatePoint(
|
||||
// organization,
|
||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
// event.object.uuid,
|
||||
// )
|
||||
const data = {
|
||||
organization,
|
||||
position: {
|
||||
x: event.object.position.x,
|
||||
y: 0.01,
|
||||
z: event.object.position.z,
|
||||
},
|
||||
uuid: event.object.uuid,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//SOCKET
|
||||
socket.emit("v1:Line:update", data);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
position: { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
uuid: event.object.uuid,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
if (state.controls) {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
socket.emit('v1:Line:update', data);
|
||||
dragPointControls.current.addEventListener("hoveron", function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(
|
||||
event.object.userData.color
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (state.controls) {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveron', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(event.object.userData.color)
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener('hoveroff', function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor))
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
dragPointControls.current.addEventListener("hoveroff", function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(
|
||||
new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,157 +1,146 @@
|
||||
import * as THREE from 'three';
|
||||
import * as THREE from "three";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from '../lines/addLineToScene';
|
||||
import splitLine from '../lines/splitLine';
|
||||
import removeReferenceLine from '../lines/removeReferenceLine';
|
||||
import getClosestIntersection from '../lines/getClosestIntersection';
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
import addLineToScene from "../lines/addLineToScene";
|
||||
import splitLine from "../lines/splitLine";
|
||||
import removeReferenceLine from "../lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../lines/getClosestIntersection";
|
||||
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function drawOnlyFloor(
|
||||
raycaster: THREE.Raycaster,
|
||||
state: Types.ThreeState,
|
||||
camera: THREE.Camera,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
onlyFloorline: Types.RefOnlyFloorLine,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?:string
|
||||
raycaster: THREE.Raycaster,
|
||||
state: Types.ThreeState,
|
||||
camera: THREE.Camera,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
onlyFloorline: Types.RefOnlyFloorLine,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
if (!plane.current) return;
|
||||
const { userId, organization, email } = getUserData();
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
const intersectsLines = raycaster.intersectObjects(
|
||||
floorPlanGroupLine.current.children,
|
||||
true
|
||||
);
|
||||
const intersectsPoint = raycaster.intersectObjects(
|
||||
floorPlanGroupPoint.current.children,
|
||||
true
|
||||
);
|
||||
const VisibleintersectsPoint = intersectsPoint.find(
|
||||
(intersect) => intersect.object.visible
|
||||
);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName
|
||||
);
|
||||
if (
|
||||
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
|
||||
intersectsLines.length > 0 &&
|
||||
!isSnapped.current &&
|
||||
!ispreSnapped.current
|
||||
) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (!plane.current) return
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
const intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible);
|
||||
const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName);
|
||||
if (
|
||||
visibleIntersect &&
|
||||
(intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.floorName ||
|
||||
intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName)
|
||||
) {
|
||||
let pointColor, lineColor;
|
||||
if (
|
||||
intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
) {
|
||||
pointColor = CONSTANTS.pointConfig.wallOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.wallColor;
|
||||
} else {
|
||||
pointColor = CONSTANTS.pointConfig.floorOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.floorColor;
|
||||
}
|
||||
let IntersectsPoint = new THREE.Vector3(
|
||||
intersects[0].point.x,
|
||||
0.01,
|
||||
intersects[0].point.z
|
||||
);
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint =
|
||||
visibleIntersect.object.geometry.parameters.path.getPoints(
|
||||
CONSTANTS.lineConfig.lineIntersectionPoints
|
||||
);
|
||||
let intersectionPoint = getClosestIntersection(
|
||||
ThroughPoint,
|
||||
IntersectsPoint
|
||||
);
|
||||
|
||||
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
pointColor,
|
||||
lineColor,
|
||||
intersectsLines[0].object.userData.linePoints[0][3],
|
||||
projectId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.floorName,
|
||||
]);
|
||||
|
||||
if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) {
|
||||
let pointColor, lineColor;
|
||||
if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) {
|
||||
pointColor = CONSTANTS.pointConfig.wallOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.wallColor;
|
||||
} else {
|
||||
pointColor = CONSTANTS.pointConfig.floorOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.floorColor;
|
||||
}
|
||||
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
|
||||
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
|
||||
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
|
||||
|
||||
if (intersectionPoint) {
|
||||
|
||||
const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3],projectId);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects.length > 0 && intersectsLines.length === 0) {
|
||||
|
||||
////////// Clicked on an empty place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
@@ -159,28 +148,126 @@ async function drawOnlyFloor(
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
versionId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
|
||||
const lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) { ////////// Add this to stop the drawing mode after snapping //////////
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.floorColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
|
||||
removeReferenceLine(
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
line
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects.length > 0 && intersectsLines.length === 0) {
|
||||
////////// Clicked on an empty place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.floorOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.floorName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.floorName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.floorColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
const lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
////////// Add this to stop the drawing mode after snapping //////////
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawOnlyFloor;
|
||||
export default drawOnlyFloor;
|
||||
|
||||
@@ -1,93 +1,104 @@
|
||||
import { toast } from 'react-toastify';
|
||||
import RemoveConnectedLines from '../lines/removeConnectedLines';
|
||||
import { toast } from "react-toastify";
|
||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
||||
|
||||
import * as Types from '../../../../types/world/worldTypes';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
|
||||
|
||||
async function DeleteLayer(
|
||||
removedLayer: Types.Number,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
setRemovedLayer: Types.setRemoveLayerSetState,
|
||||
socket: Socket<any>,
|
||||
projectId?:string
|
||||
removedLayer: Types.Number,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
setRemovedLayer: Types.setRemoveLayerSetState,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
|
||||
|
||||
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
|
||||
const removedLines: Types.Lines = lines.current.filter(
|
||||
(line) => line[0][2] === removedLayer
|
||||
);
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
const removedLines: Types.Lines = lines.current.filter(line => line[0][2] === removedLayer);
|
||||
//REST
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
// await deleteLayer(organization, removedLayer);
|
||||
|
||||
//REST
|
||||
//SOCKET
|
||||
|
||||
// await deleteLayer(organization, removedLayer);
|
||||
const data = {
|
||||
organization,
|
||||
layer: removedLayer,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//SOCKET
|
||||
socket.emit("v1:Line:delete:layer", data);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
layer: removedLayer,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
////////// Remove Points and lines from the removed layer //////////
|
||||
|
||||
removedLines.forEach((line) => {
|
||||
line.forEach((removedPoint) => {
|
||||
RemoveConnectedLines(
|
||||
removedPoint[1],
|
||||
floorPlanGroupLine,
|
||||
floorPlanGroupPoint,
|
||||
setDeletedLines,
|
||||
lines
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
////////// Update the remaining lines layer values in the userData and in lines.current //////////
|
||||
|
||||
let remaining = lines.current.filter((line) => line[0][2] !== removedLayer);
|
||||
let updatedLines: Types.Lines = [];
|
||||
remaining.forEach((line) => {
|
||||
let newLines: Types.Line = [...line];
|
||||
if (newLines[0][2] > removedLayer) {
|
||||
newLines[0][2] -= 1;
|
||||
newLines[1][2] -= 1;
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:delete:layer', data);
|
||||
|
||||
////////// Remove Points and lines from the removed layer //////////
|
||||
|
||||
removedLines.forEach((line) => {
|
||||
line.forEach((removedPoint) => {
|
||||
RemoveConnectedLines(removedPoint[1], floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
});
|
||||
});
|
||||
|
||||
////////// Update the remaining lines layer values in the userData and in lines.current //////////
|
||||
|
||||
let remaining = lines.current.filter(line => line[0][2] !== removedLayer);
|
||||
let updatedLines: Types.Lines = [];
|
||||
remaining.forEach(line => {
|
||||
let newLines: Types.Line = [...line];
|
||||
if (newLines[0][2] > removedLayer) {
|
||||
newLines[0][2] -= 1;
|
||||
newLines[1][2] -= 1;
|
||||
}
|
||||
|
||||
const matchingLine = floorPlanGroupLine.current.children.find(l => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
|
||||
if (matchingLine) {
|
||||
const updatedUserData = matchingLine.userData;
|
||||
updatedUserData.linePoints[0][2] = newLines[0][2];
|
||||
updatedUserData.linePoints[1][2] = newLines[1][2];
|
||||
}
|
||||
updatedLines.push(newLines);
|
||||
});
|
||||
|
||||
lines.current = updatedLines;
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
////////// Also remove OnlyFloorLines and update it in localstorage //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
|
||||
return floor[0][0][2] !== removedLayer;
|
||||
});
|
||||
const meshToRemove: any = floorGroup.current?.children.find((mesh) =>
|
||||
mesh.name === `Only_Floor_Line_${removedLayer}`
|
||||
const matchingLine = floorPlanGroupLine.current.children.find(
|
||||
(l) =>
|
||||
l.userData.linePoints[0][1] === line[0][1] &&
|
||||
l.userData.linePoints[1][1] === line[1][1]
|
||||
);
|
||||
if (meshToRemove) {
|
||||
(<any>meshToRemove.material).dispose();
|
||||
(<any>meshToRemove.geometry).dispose();
|
||||
floorGroup.current?.remove(meshToRemove);
|
||||
if (matchingLine) {
|
||||
const updatedUserData = matchingLine.userData;
|
||||
updatedUserData.linePoints[0][2] = newLines[0][2];
|
||||
updatedUserData.linePoints[1][2] = newLines[1][2];
|
||||
}
|
||||
updatedLines.push(newLines);
|
||||
});
|
||||
|
||||
echo.success("Layer Removed!");
|
||||
setRemovedLayer(null);
|
||||
lines.current = updatedLines;
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
////////// Also remove OnlyFloorLines and update it in localstorage //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
|
||||
return floor[0][0][2] !== removedLayer;
|
||||
});
|
||||
const meshToRemove: any = floorGroup.current?.children.find(
|
||||
(mesh) => mesh.name === `Only_Floor_Line_${removedLayer}`
|
||||
);
|
||||
if (meshToRemove) {
|
||||
(<any>meshToRemove.material).dispose();
|
||||
(<any>meshToRemove.geometry).dispose();
|
||||
floorGroup.current?.remove(meshToRemove);
|
||||
}
|
||||
|
||||
echo.success("Layer Removed!");
|
||||
setRemovedLayer(null);
|
||||
}
|
||||
export default DeleteLayer;
|
||||
|
||||
@@ -2,91 +2,91 @@ import { Socket } from "socket.io-client";
|
||||
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
import { toast } from "react-toastify";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
function deleteLine(
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>,
|
||||
projectId?: string
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): void {
|
||||
const { userId, organization, email } = getUserData();
|
||||
////////// Deleting a line and the points if they are not connected to any other line //////////
|
||||
|
||||
////////// Deleting a line and the points if they are not connected to any other line //////////
|
||||
if (!hoveredDeletableLine.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hoveredDeletableLine.current) {
|
||||
return;
|
||||
}
|
||||
const linePoints = hoveredDeletableLine.current.userData.linePoints;
|
||||
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
|
||||
|
||||
const linePoints = hoveredDeletableLine.current.userData.linePoints;
|
||||
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
|
||||
//REST
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": linePoints[0][1] },
|
||||
// { "uuid": linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//REST
|
||||
//SOCKET
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": linePoints[0][1] },
|
||||
// { "uuid": linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
const data = {
|
||||
organization,
|
||||
line: [{ uuid: linePoints[0][1] }, { uuid: linePoints[1][1] }],
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//SOCKET
|
||||
socket.emit("v1:Line:delete", data);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": linePoints[0][1] },
|
||||
{ "uuid": linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
onlyFloorlines.current = onlyFloorlines.current
|
||||
.map((floorline) =>
|
||||
floorline.filter(
|
||||
(line) =>
|
||||
line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]
|
||||
)
|
||||
)
|
||||
.filter((floorline) => floorline.length > 0);
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
lines.current = lines.current.filter((item) => item !== linePoints);
|
||||
(<any>hoveredDeletableLine.current.material).dispose();
|
||||
(<any>hoveredDeletableLine.current.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
|
||||
setDeletedLines([linePoints]);
|
||||
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
lines.current = lines.current.filter(item => item !== linePoints);
|
||||
(<any>hoveredDeletableLine.current.material).dispose();
|
||||
(<any>hoveredDeletableLine.current.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
|
||||
setDeletedLines([linePoints]);
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
echo.success("Line Removed!");
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
echo.success("Line Removed!");
|
||||
}
|
||||
|
||||
export default deleteLine;
|
||||
|
||||
@@ -15,6 +15,8 @@ import * as Types from "../../../../../types/world/worldTypes";
|
||||
import getRoomsFromLines from "../getRoomsFromLines";
|
||||
import * as turf from '@turf/turf';
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { useVersionContext } from "../../../version/versionContext";
|
||||
|
||||
const DistanceText = () => {
|
||||
const [lines, setLines] = useState<
|
||||
@@ -31,7 +33,10 @@ const DistanceText = () => {
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
const [linesState, setLinesState] = useState<Types.Lines>([]);
|
||||
const { roomsState, setRoomsState } = useRoomsState();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { organization, email } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -93,11 +98,9 @@ const DistanceText = () => {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem("email");
|
||||
if (!email) return;
|
||||
const organization = email.split("@")[1].split(".")[0];
|
||||
|
||||
getLines(organization,projectId).then((data) => {
|
||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
setLinesState(data);
|
||||
|
||||
@@ -127,7 +130,7 @@ const DistanceText = () => {
|
||||
});
|
||||
setLines(lines);
|
||||
});
|
||||
}, [activeLayer]);
|
||||
}, [activeLayer, selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
|
||||
@@ -1,146 +1,129 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from './addLineToScene';
|
||||
import splitLine from './splitLine';
|
||||
import removeReferenceLine from './removeReferenceLine';
|
||||
import getClosestIntersection from './getClosestIntersection';
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
import addLineToScene from "./addLineToScene";
|
||||
import splitLine from "./splitLine";
|
||||
import removeReferenceLine from "./removeReferenceLine";
|
||||
import getClosestIntersection from "./getClosestIntersection";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from './lineConvertions/arrayLineToObject';
|
||||
import arrayLineToObject from "./lineConvertions/arrayLineToObject";
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function drawWall(
|
||||
raycaster: THREE.Raycaster,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string
|
||||
raycaster: THREE.Raycaster,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
const { userId, organization, email } = getUserData();
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
||||
|
||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
||||
if (!plane.current) return;
|
||||
let intersects = raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let intersectsLines = raycaster.intersectObjects(
|
||||
floorPlanGroupLine.current.children,
|
||||
true
|
||||
);
|
||||
let intersectsPoint = raycaster.intersectObjects(
|
||||
floorPlanGroupPoint.current.children,
|
||||
true
|
||||
);
|
||||
|
||||
if (!plane.current) return
|
||||
let intersects = raycaster.intersectObject(plane.current, true);
|
||||
const VisibleintersectsPoint = intersectsPoint.find(
|
||||
(intersect) => intersect.object.visible
|
||||
);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName &&
|
||||
intersect.object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
|
||||
let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
|
||||
let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
if (
|
||||
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
|
||||
intersectsLines.length > 0 &&
|
||||
!isSnapped.current &&
|
||||
!ispreSnapped.current
|
||||
) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible);
|
||||
const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName && intersect.object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName);
|
||||
if (visibleIntersect && intersects) {
|
||||
let IntersectsPoint = new THREE.Vector3(
|
||||
intersects[0].point.x,
|
||||
0.01,
|
||||
intersects[0].point.z
|
||||
);
|
||||
|
||||
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint =
|
||||
visibleIntersect.object.geometry.parameters.path.getPoints(
|
||||
CONSTANTS.lineConfig.lineIntersectionPoints
|
||||
);
|
||||
let intersectionPoint = getClosestIntersection(
|
||||
ThroughPoint,
|
||||
IntersectsPoint
|
||||
);
|
||||
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
projectId,
|
||||
versionId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
if (visibleIntersect && intersects) {
|
||||
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
|
||||
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
|
||||
|
||||
if (intersectionPoint) {
|
||||
|
||||
const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, CONSTANTS.pointConfig.wallOuterColor, CONSTANTS.lineConfig.wallColor, CONSTANTS.lineConfig.wallName,projectId);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
|
||||
////////// Clicked on a emply place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.wallOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.wallName);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
@@ -148,27 +131,115 @@ async function drawWall(
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization: organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current])
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
////////// Clicked on a emply place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawWall;
|
||||
|
||||
@@ -5,11 +5,11 @@ import * as Types from "../../../../types/world/worldTypes";
|
||||
function getClosestIntersection(
|
||||
intersects: Types.Vector3Array,
|
||||
point: Types.Vector3
|
||||
): Types.Vector3 | null {
|
||||
): Types.Vector3 {
|
||||
|
||||
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
|
||||
|
||||
let closestNewPoint: THREE.Vector3 | null = null;
|
||||
let closestNewPoint: THREE.Vector3 = point;
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const intersect of intersects) {
|
||||
|
||||
@@ -1,132 +1,151 @@
|
||||
import * as THREE from 'three';
|
||||
import * as THREE from "three";
|
||||
|
||||
import addLineToScene from './addLineToScene';
|
||||
import addPointToScene from '../points/addPointToScene';
|
||||
import addLineToScene from "./addLineToScene";
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
|
||||
function splitLine(
|
||||
visibleIntersect: Types.IntersectionEvent,
|
||||
intersectionPoint: Types.Vector3,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
isSnappedUUID: Types.RefString,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
floorPlanGroupLine: { current: THREE.Group },
|
||||
socket: Socket<any>,
|
||||
pointColor: Types.String,
|
||||
lineColor: Types.String,
|
||||
lineType: Types.String,
|
||||
projectId?: string
|
||||
visibleIntersect: Types.IntersectionEvent,
|
||||
intersectionPoint: Types.Vector3,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
isSnappedUUID: Types.RefString,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
floorPlanGroupLine: { current: THREE.Group },
|
||||
socket: Socket<any>,
|
||||
pointColor: Types.String,
|
||||
lineColor: Types.String,
|
||||
lineType: Types.String,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): [Types.Line, Types.Line] {
|
||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
||||
|
||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
||||
const { userId, organization, email } = getUserData();
|
||||
(visibleIntersect.object as any).material.dispose();
|
||||
(visibleIntersect.object as any).geometry.dispose();
|
||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
||||
|
||||
//REST
|
||||
|
||||
((visibleIntersect.object as any).material).dispose();
|
||||
((visibleIntersect.object as any).geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
//SOCKET
|
||||
|
||||
//REST
|
||||
const data = {
|
||||
organization,
|
||||
line: [
|
||||
{ uuid: visibleIntersect.object.userData.linePoints[0][1] },
|
||||
{ uuid: visibleIntersect.object.userData.linePoints[1][1] },
|
||||
],
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
socket.emit("v1:Line:delete", data);
|
||||
|
||||
//SOCKET
|
||||
const point = addPointToScene(
|
||||
intersectionPoint,
|
||||
pointColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lineType
|
||||
);
|
||||
|
||||
const oldLinePoints = visibleIntersect.object.userData.linePoints;
|
||||
lines.current = lines.current.filter((item) => item !== oldLinePoints);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
line: [
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
],
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
const clickedPoint: Types.Point = [
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
point.uuid,
|
||||
oldLinePoints[0][2],
|
||||
lineType,
|
||||
];
|
||||
|
||||
socket.emit('v1:Line:delete', data);
|
||||
const start = oldLinePoints[0];
|
||||
const end = oldLinePoints[1];
|
||||
|
||||
const point = addPointToScene(intersectionPoint, pointColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lineType);
|
||||
const newLine1: Types.Line = [start, clickedPoint];
|
||||
const newLine2: Types.Line = [clickedPoint, end];
|
||||
|
||||
const oldLinePoints = visibleIntersect.object.userData.linePoints;
|
||||
lines.current = lines.current.filter(item => item !== oldLinePoints);
|
||||
const line1 = arrayLineToObject(newLine1);
|
||||
const line2 = arrayLineToObject(newLine2);
|
||||
|
||||
const clickedPoint: Types.Point = [
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
point.uuid,
|
||||
oldLinePoints[0][2],
|
||||
lineType
|
||||
];
|
||||
//REST
|
||||
|
||||
const start = oldLinePoints[0];
|
||||
const end = oldLinePoints[1];
|
||||
// setLine(organization, line1.layer!, line1.line!, line1.type!);
|
||||
|
||||
const newLine1: Types.Line = [start, clickedPoint];
|
||||
const newLine2: Types.Line = [clickedPoint, end];
|
||||
//SOCKET
|
||||
|
||||
const line1 = arrayLineToObject(newLine1);
|
||||
const line2 = arrayLineToObject(newLine2);
|
||||
const input1 = {
|
||||
organization,
|
||||
layer: line1.layer,
|
||||
line: line1.line,
|
||||
type: line1.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//REST
|
||||
socket.emit("v1:Line:create", input1);
|
||||
|
||||
// setLine(organization, line1.layer!, line1.line!, line1.type!);
|
||||
//REST
|
||||
|
||||
//SOCKET
|
||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
||||
|
||||
const input1 = {
|
||||
organization: organization,
|
||||
layer: line1.layer,
|
||||
line: line1.line,
|
||||
type: line1.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
//SOCKET
|
||||
|
||||
socket.emit('v1:Line:create', input1);
|
||||
const input2 = {
|
||||
organization,
|
||||
layer: line2.layer,
|
||||
line: line2.line,
|
||||
type: line2.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//REST
|
||||
socket.emit("v1:Line:create", input2);
|
||||
|
||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
//SOCKET
|
||||
addLineToScene(
|
||||
newLine1[0][0],
|
||||
newLine1[1][0],
|
||||
lineColor,
|
||||
newLine1,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
addLineToScene(
|
||||
newLine2[0][0],
|
||||
newLine2[1][0],
|
||||
lineColor,
|
||||
newLine2,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
|
||||
const input2 = {
|
||||
organization: organization,
|
||||
layer: line2.layer,
|
||||
line: line2.line,
|
||||
type: line2.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
|
||||
socket.emit('v1:Line:create', input2);
|
||||
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
addLineToScene(newLine1[0][0], newLine1[1][0], lineColor, newLine1, floorPlanGroupLine);
|
||||
addLineToScene(newLine2[0][0], newLine2[1][0], lineColor, newLine2, floorPlanGroupLine);
|
||||
|
||||
return [newLine1, newLine2];
|
||||
return [newLine1, newLine2];
|
||||
}
|
||||
|
||||
export default splitLine;
|
||||
|
||||
@@ -1,62 +1,72 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from 'react-toastify';
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
||||
// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
function deletePoint(
|
||||
hoveredDeletablePoint: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>,
|
||||
projectId?:string
|
||||
hoveredDeletablePoint: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): void {
|
||||
////////// Deleting a Point and the lines that are connected to it //////////
|
||||
////////// Deleting a Point and the lines that are connected to it //////////
|
||||
|
||||
if (!hoveredDeletablePoint.current) {
|
||||
return;
|
||||
}
|
||||
if (!hoveredDeletablePoint.current) {
|
||||
return;
|
||||
}
|
||||
const { userId, organization, email } = getUserData();
|
||||
(<any>hoveredDeletablePoint.current.material).dispose();
|
||||
(<any>hoveredDeletablePoint.current.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
|
||||
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
|
||||
|
||||
(<any>hoveredDeletablePoint.current.material).dispose();
|
||||
(<any>hoveredDeletablePoint.current.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
|
||||
const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
|
||||
//REST
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
// deletePointApi(organization, DeletedPointUUID);
|
||||
|
||||
//REST
|
||||
//SOCKET
|
||||
|
||||
// deletePointApi(organization, DeletedPointUUID);
|
||||
const data = {
|
||||
organization,
|
||||
uuid: DeletedPointUUID,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
//SOCKET
|
||||
// console.log('data: ', data);
|
||||
socket.emit("v1:Line:delete:point", data);
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
uuid: DeletedPointUUID,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
////////// Update onlyFloorlines.current to remove references to the deleted point //////////
|
||||
|
||||
// console.log('data: ', data);
|
||||
socket.emit('v1:Line:delete:point', data);
|
||||
onlyFloorlines.current = onlyFloorlines.current
|
||||
.map((floorline) =>
|
||||
floorline.filter(
|
||||
(line) =>
|
||||
line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID
|
||||
)
|
||||
)
|
||||
.filter((floorline) => floorline.length > 0);
|
||||
|
||||
////////// Update onlyFloorlines.current to remove references to the deleted point //////////
|
||||
RemoveConnectedLines(
|
||||
DeletedPointUUID,
|
||||
floorPlanGroupLine,
|
||||
floorPlanGroupPoint,
|
||||
setDeletedLines,
|
||||
lines
|
||||
);
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
|
||||
floorline.filter(line => line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID)
|
||||
).filter(floorline => floorline.length > 0);
|
||||
|
||||
RemoveConnectedLines(DeletedPointUUID, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
|
||||
|
||||
echo.success("Point Removed!");
|
||||
echo.success("Point Removed!");
|
||||
}
|
||||
|
||||
export default deletePoint;
|
||||
|
||||
@@ -1,142 +1,164 @@
|
||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { toast } from 'react-toastify';
|
||||
import * as THREE from 'three';
|
||||
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { toast } from "react-toastify";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function AddWallItems(
|
||||
selected: any,
|
||||
raycaster: THREE.Raycaster,
|
||||
CSGGroup: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
socket: Socket<any>,
|
||||
projectId?: string
|
||||
selected: any,
|
||||
raycaster: THREE.Raycaster,
|
||||
CSGGroup: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
): Promise<void> {
|
||||
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
|
||||
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
if (!wallRaycastIntersection) return;
|
||||
const { userId, organization } = getUserData();
|
||||
let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
|
||||
const wallRaycastIntersection = intersects?.find((child) =>
|
||||
child.object.name.includes("WallRaycastReference")
|
||||
);
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
const intersectionPoint = wallRaycastIntersection;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
if (!wallRaycastIntersection) return;
|
||||
|
||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
const intersectionPoint = wallRaycastIntersection;
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
// Check THREE.js cache first
|
||||
const cachedModel = THREE.Cache.get(selected.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(cachedModel);
|
||||
return;
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
// Check THREE.js cache first
|
||||
const cachedModel = THREE.Cache.get(selected.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(cachedModel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check IndexedDB cache
|
||||
const cachedModelBlob = await retrieveGLTF(selected.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selected.id, gltf);
|
||||
handleModelLoad(gltf);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Load from backend if not in any cache
|
||||
loader.load(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`,
|
||||
async (gltf) => {
|
||||
try {
|
||||
const modelBlob = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`
|
||||
).then((res) => res.blob());
|
||||
await storeGLTF(selected.id, modelBlob);
|
||||
THREE.Cache.add(selected.id, gltf);
|
||||
await handleModelLoad(gltf);
|
||||
} catch (error) {
|
||||
console.error("Failed to cache model:", error);
|
||||
handleModelLoad(gltf);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Check IndexedDB cache
|
||||
const cachedModelBlob = await retrieveGLTF(selected.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selected.id, gltf);
|
||||
handleModelLoad(gltf);
|
||||
});
|
||||
return;
|
||||
}
|
||||
async function handleModelLoad(gltf: GLTF) {
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = { wall: intersectionPoint.object.parent };
|
||||
|
||||
// Load from backend if not in any cache
|
||||
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`, async (gltf) => {
|
||||
try {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selected.id, modelBlob);
|
||||
THREE.Cache.add(selected.id, gltf);
|
||||
await handleModelLoad(gltf);
|
||||
} catch (error) {
|
||||
console.error('Failed to cache model:', error);
|
||||
handleModelLoad(gltf);
|
||||
}
|
||||
model.children[0].children.forEach((child) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleModelLoad(gltf: GLTF) {
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = { wall: intersectionPoint.object.parent };
|
||||
const boundingBox = new THREE.Box3().setFromObject(model);
|
||||
const size = new THREE.Vector3();
|
||||
boundingBox.getSize(size);
|
||||
|
||||
model.children[0].children.forEach((child) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
const csgscale = [size.x, size.y, size.z] as [number, number, number];
|
||||
|
||||
const boundingBox = new THREE.Box3().setFromObject(model);
|
||||
const size = new THREE.Vector3();
|
||||
boundingBox.getSize(size);
|
||||
const center = new THREE.Vector3();
|
||||
boundingBox.getCenter(center);
|
||||
const csgposition = [center.x, center.y, center.z] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
];
|
||||
|
||||
const csgscale = [size.x, size.y, size.z] as [number, number, number];
|
||||
|
||||
const center = new THREE.Vector3();
|
||||
boundingBox.getCenter(center);
|
||||
const csgposition = [center.x, center.y, center.z] as [number, number, number];
|
||||
|
||||
let positionY = selected.subCategory === 'fixed-move' ? 0 : intersectionPoint.point.y;
|
||||
if (positionY === 0) {
|
||||
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
|
||||
}
|
||||
|
||||
const newWallItem = {
|
||||
type: selected.subCategory,
|
||||
model: model,
|
||||
modelName: selected.name,
|
||||
assetId: selected.id,
|
||||
scale: [1, 1, 1] as [number, number, number],
|
||||
csgscale: csgscale,
|
||||
csgposition: csgposition,
|
||||
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
|
||||
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
|
||||
};
|
||||
|
||||
const email = localStorage.getItem('email');
|
||||
const organization = email ? (email.split("@")[1]).split(".")[0] : 'default';
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modelUuid: model.uuid,
|
||||
modelName: newWallItem.modelName,
|
||||
assetId: selected.id,
|
||||
type: selected.subCategory,
|
||||
csgposition: newWallItem.csgposition,
|
||||
csgscale: newWallItem.csgscale,
|
||||
position: newWallItem.position,
|
||||
quaternion: newWallItem.quaternion,
|
||||
scale: newWallItem.scale,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
};
|
||||
|
||||
socket.emit('v1:wallItems:set', data);
|
||||
|
||||
setWallItems((prevItems) => {
|
||||
const updatedItems = [...prevItems, newWallItem];
|
||||
|
||||
const WallItemsForStorage = updatedItems.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modelUuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
echo.success("Model Added!");
|
||||
return updatedItems;
|
||||
});
|
||||
let positionY =
|
||||
selected.subCategory === "fixed-move" ? 0 : intersectionPoint.point.y;
|
||||
if (positionY === 0) {
|
||||
positionY =
|
||||
Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) *
|
||||
CONSTANTS.wallConfig.height;
|
||||
}
|
||||
|
||||
const newWallItem = {
|
||||
type: selected.subCategory,
|
||||
model: model,
|
||||
modelName: selected.name,
|
||||
assetId: selected.id,
|
||||
scale: [1, 1, 1] as [number, number, number],
|
||||
csgscale: csgscale,
|
||||
csgposition: csgposition,
|
||||
position: [
|
||||
intersectionPoint.point.x,
|
||||
positionY,
|
||||
intersectionPoint.point.z,
|
||||
] as [number, number, number],
|
||||
quaternion:
|
||||
intersectionPoint.object.quaternion.clone() as Types.QuaternionType,
|
||||
};
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: model.uuid,
|
||||
modelName: newWallItem.modelName,
|
||||
assetId: selected.id,
|
||||
type: selected.subCategory,
|
||||
csgposition: newWallItem.csgposition,
|
||||
csgscale: newWallItem.csgscale,
|
||||
position: newWallItem.position,
|
||||
quaternion: newWallItem.quaternion,
|
||||
scale: newWallItem.scale,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:wallItems:set", data);
|
||||
|
||||
setWallItems((prevItems) => {
|
||||
const updatedItems = [...prevItems, newWallItem];
|
||||
|
||||
const WallItemsForStorage = updatedItems.map((item) => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modelUuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
echo.success("Model Added!");
|
||||
return updatedItems;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AddWallItems;
|
||||
export default AddWallItems;
|
||||
|
||||
@@ -1,60 +1,62 @@
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { Socket } from "socket.io-client";
|
||||
|
||||
function DeleteWallItems(
|
||||
hoveredDeletableWallItem: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
wallItems: Types.wallItems,
|
||||
socket: Socket<any>,
|
||||
projectId?: string
|
||||
hoveredDeletableWallItem: Types.RefMesh,
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
wallItems: Types.wallItems,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId? : string,
|
||||
): void {
|
||||
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
|
||||
const { userId, organization, email } = getUserData();
|
||||
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current) {
|
||||
setWallItems([]);
|
||||
let WallItemsRef = wallItems;
|
||||
const removedItem = WallItemsRef.find(
|
||||
(item) => item.model?.uuid === hoveredDeletableWallItem.current?.uuid
|
||||
);
|
||||
const Items = WallItemsRef.filter(
|
||||
(item) => item.model?.uuid !== hoveredDeletableWallItem.current?.uuid
|
||||
);
|
||||
|
||||
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
|
||||
setTimeout(async () => {
|
||||
WallItemsRef = Items;
|
||||
setWallItems(WallItemsRef);
|
||||
|
||||
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current) {
|
||||
setWallItems([]);
|
||||
let WallItemsRef = wallItems;
|
||||
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.uuid);
|
||||
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.uuid);
|
||||
//REST
|
||||
|
||||
setTimeout(async () => {
|
||||
WallItemsRef = Items;
|
||||
setWallItems(WallItemsRef);
|
||||
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!)
|
||||
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
//SOCKET
|
||||
|
||||
//REST
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: removedItem?.model?.uuid!,
|
||||
modelName: removedItem?.modelName!,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
versionId,
|
||||
userId,
|
||||
};
|
||||
|
||||
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelName!)
|
||||
socket.emit("v1:wallItems:delete", data);
|
||||
|
||||
//SOCKET
|
||||
const WallItemsForStorage = WallItemsRef.map((item) => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modelUuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
modelUuid: removedItem?.model?.uuid!,
|
||||
modelName: removedItem?.modelName!,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
|
||||
socket.emit('v1:wallItems:delete', data);
|
||||
|
||||
const WallItemsForStorage = WallItemsRef.map(item => {
|
||||
const { model, ...rest } = item;
|
||||
return {
|
||||
...rest,
|
||||
modelUuid: model?.uuid,
|
||||
};
|
||||
});
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
hoveredDeletableWallItem.current = null;
|
||||
}, 50);
|
||||
}
|
||||
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
|
||||
hoveredDeletableWallItem.current = null;
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
export default DeleteWallItems;
|
||||
|
||||
@@ -17,6 +17,8 @@ import drawWall from "../geomentries/lines/drawWall";
|
||||
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
|
||||
import addDragControl from "../eventDeclaration/dragControlDeclaration";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
|
||||
const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
|
||||
const state = useThree();
|
||||
@@ -29,11 +31,14 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
|
||||
const { setNewLines } = useNewLines();
|
||||
const { setDeletedLines } = useDeletedLines();
|
||||
const { socket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { organization } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode === 'move') {
|
||||
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket, projectId);
|
||||
addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket, projectId, selectedVersion?.versionId || '',);
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -44,17 +49,11 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
|
||||
}, [toolMode, state]);
|
||||
|
||||
useEffect(() => {
|
||||
const email = localStorage.getItem('email')
|
||||
const organization = (email!.split("@")[1]).split(".")[0];
|
||||
|
||||
// Load data from localStorage if available
|
||||
getLines(organization, projectId).then((data) => {
|
||||
// console.log('data: ', data);
|
||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
|
||||
// const data = localStorage.getItem("Lines");
|
||||
|
||||
if (Lines) {
|
||||
lines.current = Lines;
|
||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
@@ -62,7 +61,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
|
||||
setUpdateScene(true);
|
||||
}
|
||||
})
|
||||
}, []);
|
||||
}, [selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView) {
|
||||
@@ -94,7 +93,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
|
||||
|
||||
useEffect(() => {
|
||||
if (removedLayer !== null) {
|
||||
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket, projectId);
|
||||
DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket, projectId, selectedVersion?.versionId || '',);
|
||||
}
|
||||
}, [removedLayer]);
|
||||
|
||||
@@ -140,19 +139,19 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
|
||||
|
||||
if (toolMode === "2D-Delete") {
|
||||
if (hoveredDeletablePoint.current !== null) {
|
||||
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket, projectId);
|
||||
deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
|
||||
}
|
||||
if (hoveredDeletableLine.current !== null) {
|
||||
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket, projectId);
|
||||
deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket, projectId, selectedVersion?.versionId || '',);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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") {
|
||||
drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId);
|
||||
drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import loadInitialWallItems from "../IntialLoad/loadInitialWallItems";
|
||||
import AddWallItems from "../geomentries/walls/addWallItems";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
|
||||
const WallItemsGroup = ({
|
||||
currentWallItem,
|
||||
@@ -37,12 +39,16 @@ const WallItemsGroup = ({
|
||||
const { setSelectedWallItem } = useSelectedWallItem();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedItem } = useSelectedItem();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
// Load Wall Items from the backend
|
||||
loadInitialWallItems(setWallItems, projectId);
|
||||
}, []);
|
||||
if (!projectId || !selectedVersion) return;
|
||||
loadInitialWallItems(setWallItems, projectId, selectedVersion?.versionId);
|
||||
}, [selectedVersion?.versionId]);
|
||||
|
||||
////////// Update the Position value changes in the selected item //////////
|
||||
|
||||
@@ -120,9 +126,6 @@ const WallItemsGroup = ({
|
||||
});
|
||||
|
||||
setTimeout(async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
const userId = localStorage.getItem("userId");
|
||||
|
||||
//REST
|
||||
|
||||
@@ -142,7 +145,7 @@ const WallItemsGroup = ({
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization: organization,
|
||||
organization,
|
||||
modelUuid: currentItem.model?.uuid!,
|
||||
assetId: currentItem.assetId,
|
||||
modelName: currentItem.modelName!,
|
||||
@@ -153,6 +156,7 @@ const WallItemsGroup = ({
|
||||
quaternion: currentItem.quaternion,
|
||||
scale: currentItem.scale!,
|
||||
socketId: socket.id,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
};
|
||||
@@ -172,7 +176,7 @@ const WallItemsGroup = ({
|
||||
canvasElement.removeEventListener("pointermove", handlePointerMove);
|
||||
canvasElement.removeEventListener("pointerup", handlePointerUp);
|
||||
};
|
||||
}, [selectedItemsIndex]);
|
||||
}, [selectedItemsIndex, selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = state.gl.domElement;
|
||||
@@ -194,7 +198,9 @@ const WallItemsGroup = ({
|
||||
hoveredDeletableWallItem,
|
||||
setWallItems,
|
||||
wallItems,
|
||||
socket, projectId
|
||||
socket,
|
||||
projectId,
|
||||
selectedVersion?.versionId || '',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +220,7 @@ const WallItemsGroup = ({
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
if (selectedItem.id) {
|
||||
if (selectedItem.id && selectedVersion && projectId) {
|
||||
if (selectedItem.subCategory) {
|
||||
AddWallItems(
|
||||
selectedItem,
|
||||
@@ -222,7 +228,8 @@ const WallItemsGroup = ({
|
||||
CSGGroup,
|
||||
setWallItems,
|
||||
socket,
|
||||
projectId
|
||||
projectId,
|
||||
selectedVersion?.versionId || '',
|
||||
);
|
||||
}
|
||||
event.preventDefault();
|
||||
@@ -246,7 +253,7 @@ const WallItemsGroup = ({
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [toolMode, wallItems, selectedItem, camera]);
|
||||
}, [toolMode, wallItems, selectedItem, camera, selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toolMode && activeModule === "builder") {
|
||||
|
||||
@@ -10,18 +10,20 @@ import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLines
|
||||
import loadWalls from "../geomentries/walls/loadWalls";
|
||||
import texturePath from "../../../assets/textures/floor/wall-tex.png";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
|
||||
const WallsMeshComponent = ({ lines }: any) => {
|
||||
const { walls, setWalls } = useWalls();
|
||||
const { updateScene, setUpdateScene } = useUpdateScene();
|
||||
const { projectId } = useParams();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { organization } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
if (updateScene) {
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
getLines(organization,projectId).then((data) => {
|
||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
const Lines: Types.Lines = objectLinesToArray(data);
|
||||
localStorage.setItem("Lines", JSON.stringify(Lines));
|
||||
|
||||
@@ -31,7 +33,7 @@ const WallsMeshComponent = ({ lines }: any) => {
|
||||
});
|
||||
setUpdateScene(false);
|
||||
}
|
||||
}, [updateScene]);
|
||||
}, [updateScene, selectedVersion?.versionId]);
|
||||
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
const wallTexture = textureLoader.load(texturePath);
|
||||
|
||||
@@ -18,6 +18,8 @@ import * as turf from "@turf/turf";
|
||||
import { computeArea } from "../functions/computeArea";
|
||||
import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
|
||||
const ZoneGroup: React.FC = () => {
|
||||
const { camera, pointer, gl, raycaster, scene, controls } = useThree();
|
||||
@@ -27,19 +29,17 @@ const ZoneGroup: React.FC = () => {
|
||||
const { zonePoints, setZonePoints } = useZonePoints();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(
|
||||
null
|
||||
);
|
||||
const plane = useMemo(
|
||||
() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
|
||||
[]
|
||||
);
|
||||
const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null);
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const { toggleView } = useToggleView();
|
||||
const { removedLayer, setRemovedLayer } = useRemovedLayer();
|
||||
const { toolMode } = useToolMode();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { socket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization, email } = getUserData();
|
||||
|
||||
const groupsRef = useRef<any>();
|
||||
|
||||
@@ -72,15 +72,8 @@ const ZoneGroup: React.FC = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZones = async () => {
|
||||
const email = localStorage.getItem("email");
|
||||
if (!email) return;
|
||||
|
||||
const organization = email.split("@")[1].split(".")[0];
|
||||
const data = await getZonesApi(organization, projectId);
|
||||
// console.log('data: ', data);
|
||||
|
||||
if (data.length > 0) {
|
||||
getZonesApi(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
if (data && data.length > 0) {
|
||||
const fetchedZones = data.map((zone: any) => ({
|
||||
zoneUuid: zone.zoneUuid,
|
||||
zoneName: zone.zoneName,
|
||||
@@ -97,11 +90,13 @@ const ZoneGroup: React.FC = () => {
|
||||
);
|
||||
|
||||
setZonePoints(fetchedPoints);
|
||||
}else{
|
||||
setZones([]);
|
||||
}
|
||||
};
|
||||
|
||||
fetchZones();
|
||||
}, []);
|
||||
}).catch((err)=>{
|
||||
console.error(err);
|
||||
})
|
||||
}, [selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("zones", JSON.stringify(zones));
|
||||
@@ -142,9 +137,6 @@ const ZoneGroup: React.FC = () => {
|
||||
points: [number, number, number][];
|
||||
layer: string;
|
||||
}) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const calculateCenter = (points: number[][]) => {
|
||||
if (!points || points.length === 0) return null;
|
||||
@@ -171,8 +163,9 @@ const ZoneGroup: React.FC = () => {
|
||||
|
||||
const input = {
|
||||
userId: userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneData: {
|
||||
zoneName: zone.zoneName,
|
||||
zoneUuid: zone.zoneUuid,
|
||||
@@ -193,9 +186,6 @@ const ZoneGroup: React.FC = () => {
|
||||
points: [number, number, number][];
|
||||
layer: string;
|
||||
}) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const calculateCenter = (points: number[][]) => {
|
||||
if (!points || points.length === 0) return null;
|
||||
@@ -222,8 +212,9 @@ const ZoneGroup: React.FC = () => {
|
||||
|
||||
const input = {
|
||||
userId: userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneData: {
|
||||
zoneName: zone.zoneName,
|
||||
zoneUuid: zone.zoneUuid,
|
||||
@@ -238,14 +229,12 @@ const ZoneGroup: React.FC = () => {
|
||||
};
|
||||
|
||||
const deleteZoneFromBackend = async (zoneUuid: string) => {
|
||||
const email = localStorage.getItem("email");
|
||||
const userId = localStorage.getItem("userId");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
|
||||
const input = {
|
||||
userId: userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
organization: organization,
|
||||
organization,
|
||||
zoneUuid: zoneUuid,
|
||||
};
|
||||
|
||||
@@ -447,7 +436,7 @@ const ZoneGroup: React.FC = () => {
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("contextmenu", onContext);
|
||||
};
|
||||
}, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend,]);
|
||||
}, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, zonePoints, draggedSphere, activeLayer, raycaster, pointer, controls, plane, setZones, setZonePoints, addZoneToBackend, handleDeleteZone, updateZoneToBackend, selectedVersion?.versionId]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!startPoint) return;
|
||||
|
||||
@@ -46,9 +46,10 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
|
||||
return (
|
||||
<Tube
|
||||
name={`${points[0].pointType}-Line`}
|
||||
key={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
||||
uuid={`${points[0].pointUuid}-${points[1].pointUuid}`}
|
||||
userData={points}
|
||||
userData={{ points, path }}
|
||||
args={[path, Constants.lineConfig.tubularSegments, Constants.lineConfig.radius, Constants.lineConfig.radialSegments, false]}
|
||||
>
|
||||
<meshStandardMaterial color={colors.defaultLineColor} />
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
|
||||
const SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
|
||||
const CAN_SNAP = true; // Whether snapping is enabled or not
|
||||
|
||||
export function useAislePointSnapping(point: Point) {
|
||||
const { getConnectedPoints } = useAisleStore();
|
||||
|
||||
const snapPosition = useCallback((newPosition: [number, number, number]): {
|
||||
position: [number, number, number],
|
||||
isSnapped: boolean,
|
||||
snapSources: THREE.Vector3[]
|
||||
} => {
|
||||
if (!CAN_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||
|
||||
const connectedPoints = getConnectedPoints(point.pointUuid);
|
||||
if (connectedPoints.length === 0) {
|
||||
return {
|
||||
position: newPosition,
|
||||
isSnapped: false,
|
||||
snapSources: []
|
||||
};
|
||||
}
|
||||
|
||||
const newPos = new THREE.Vector3(...newPosition);
|
||||
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
|
||||
for (const connectedPoint of connectedPoints) {
|
||||
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||
|
||||
const xDist = Math.abs(newPos.x - cPos.x);
|
||||
const zDist = Math.abs(newPos.z - cPos.z);
|
||||
|
||||
if (xDist < SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestX || xDist < closestX.dist) {
|
||||
closestX = { pos: cPos, dist: xDist };
|
||||
}
|
||||
}
|
||||
|
||||
if (zDist < SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestZ || zDist < closestZ.dist) {
|
||||
closestZ = { pos: cPos, dist: zDist };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const snappedPos = newPos.clone();
|
||||
const snapSources: THREE.Vector3[] = [];
|
||||
|
||||
if (closestX) {
|
||||
snappedPos.x = closestX.pos.x;
|
||||
snapSources.push(closestX.pos.clone());
|
||||
}
|
||||
|
||||
if (closestZ) {
|
||||
snappedPos.z = closestZ.pos.z;
|
||||
snapSources.push(closestZ.pos.clone());
|
||||
}
|
||||
|
||||
const isSnapped = snapSources.length > 0;
|
||||
|
||||
return {
|
||||
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||
isSnapped,
|
||||
snapSources
|
||||
};
|
||||
}, [point.pointUuid, getConnectedPoints]);
|
||||
|
||||
return { snapPosition };
|
||||
}
|
||||
@@ -1,15 +1,107 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useAisleStore } from '../../../../store/builder/useAisleStore';
|
||||
import * as THREE from 'three';
|
||||
import { useCallback } from 'react';
|
||||
import { useWallStore } from '../../../../store/builder/useWallStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
const SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
|
||||
const CAN_SNAP = true; // Whether snapping is enabled or not
|
||||
const CAN_POINT_SNAP = true; // Whether snapping is enabled or not
|
||||
|
||||
const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping in meters
|
||||
|
||||
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 { aisles } = useAisleStore();
|
||||
const { walls } = useWallStore();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore();
|
||||
const { walls, getConnectedPoints: getConnectedWallPoints } = useWallStore();
|
||||
|
||||
// Wall Snapping
|
||||
|
||||
const getAllOtherWallPoints = useCallback(() => {
|
||||
if (!currentPoint) return [];
|
||||
return walls.flatMap(wall =>
|
||||
wall.points.filter(point => point.pointUuid !== currentPoint.uuid)
|
||||
);
|
||||
}, [walls, currentPoint]);
|
||||
|
||||
const snapWallPoint = useCallback((position: [number, number, number]) => {
|
||||
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||
|
||||
const otherPoints = getAllOtherWallPoints();
|
||||
const currentVec = new THREE.Vector3(...position);
|
||||
for (const point of otherPoints) {
|
||||
const pointVec = new THREE.Vector3(...point.position);
|
||||
const distance = currentVec.distanceTo(pointVec);
|
||||
if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Wall') {
|
||||
return { position: point.position, isSnapped: true, snappedPoint: point };
|
||||
}
|
||||
}
|
||||
return { position: position, isSnapped: false, snappedPoint: null };
|
||||
}, [currentPoint, getAllOtherWallPoints]);
|
||||
|
||||
const snapWallAngle = useCallback((newPosition: [number, number, number]): {
|
||||
position: [number, number, number],
|
||||
isSnapped: boolean,
|
||||
snapSources: THREE.Vector3[]
|
||||
} => {
|
||||
if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||
|
||||
const connectedPoints = getConnectedWallPoints(currentPoint.uuid);
|
||||
if (connectedPoints.length === 0) {
|
||||
return {
|
||||
position: newPosition,
|
||||
isSnapped: false,
|
||||
snapSources: []
|
||||
};
|
||||
}
|
||||
|
||||
const newPos = new THREE.Vector3(...newPosition);
|
||||
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
|
||||
for (const connectedPoint of connectedPoints) {
|
||||
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||
|
||||
const xDist = Math.abs(newPos.x - cPos.x);
|
||||
const zDist = Math.abs(newPos.z - cPos.z);
|
||||
|
||||
if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestX || xDist < closestX.dist) {
|
||||
closestX = { pos: cPos, dist: xDist };
|
||||
}
|
||||
}
|
||||
|
||||
if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestZ || zDist < closestZ.dist) {
|
||||
closestZ = { pos: cPos, dist: zDist };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const snappedPos = newPos.clone();
|
||||
const snapSources: THREE.Vector3[] = [];
|
||||
|
||||
if (closestX) {
|
||||
snappedPos.x = closestX.pos.x;
|
||||
snapSources.push(closestX.pos.clone());
|
||||
}
|
||||
|
||||
if (closestZ) {
|
||||
snappedPos.z = closestZ.pos.z;
|
||||
snapSources.push(closestZ.pos.clone());
|
||||
}
|
||||
|
||||
const isSnapped = snapSources.length > 0;
|
||||
|
||||
return {
|
||||
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||
isSnapped,
|
||||
snapSources
|
||||
};
|
||||
}, [currentPoint, getConnectedAislePoints]);
|
||||
|
||||
// Aisle Snapping
|
||||
|
||||
const getAllOtherAislePoints = useCallback(() => {
|
||||
if (!currentPoint) return [];
|
||||
@@ -19,24 +111,15 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
||||
);
|
||||
}, [aisles, currentPoint]);
|
||||
|
||||
const getAllOtherWallPoints = useCallback(() => {
|
||||
if (!currentPoint) return [];
|
||||
return walls.flatMap(wall =>
|
||||
wall.points.filter(point => point.pointUuid !== currentPoint.uuid)
|
||||
);
|
||||
}, [walls, currentPoint]);
|
||||
|
||||
const checkSnapForAisle = useCallback((position: [number, number, number]) => {
|
||||
if (!currentPoint || !CAN_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||
const snapAislePoint = useCallback((position: [number, number, number]) => {
|
||||
if (!currentPoint || !CAN_POINT_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||
|
||||
const otherPoints = getAllOtherAislePoints();
|
||||
const currentVec = new THREE.Vector3(...position);
|
||||
|
||||
for (const point of otherPoints) {
|
||||
const pointVec = new THREE.Vector3(...point.position);
|
||||
const distance = currentVec.distanceTo(pointVec);
|
||||
|
||||
if (distance <= SNAP_THRESHOLD && currentPoint.pointType === 'Aisle') {
|
||||
if (distance <= POINT_SNAP_THRESHOLD && currentPoint.pointType === 'Aisle') {
|
||||
return { position: point.position, isSnapped: true, snappedPoint: point };
|
||||
}
|
||||
}
|
||||
@@ -44,23 +127,71 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string
|
||||
return { position: position, isSnapped: false, snappedPoint: null };
|
||||
}, [currentPoint, getAllOtherAislePoints]);
|
||||
|
||||
const checkSnapForWall = useCallback((position: [number, number, number]) => {
|
||||
if (!currentPoint || !CAN_SNAP) return { position: position, isSnapped: false, snappedPoint: null };
|
||||
const snapAisleAngle = useCallback((newPosition: [number, number, number]): {
|
||||
position: [number, number, number],
|
||||
isSnapped: boolean,
|
||||
snapSources: THREE.Vector3[]
|
||||
} => {
|
||||
if (!currentPoint || !CAN_ANGLE_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] };
|
||||
|
||||
const otherPoints = getAllOtherWallPoints();
|
||||
const currentVec = new THREE.Vector3(...position);
|
||||
for (const point of otherPoints) {
|
||||
const pointVec = new THREE.Vector3(...point.position);
|
||||
const distance = currentVec.distanceTo(pointVec);
|
||||
if (distance <= SNAP_THRESHOLD && currentPoint.pointType === 'Wall') {
|
||||
return { position: point.position, isSnapped: true, snappedPoint: point };
|
||||
const connectedPoints = getConnectedAislePoints(currentPoint.uuid);
|
||||
if (connectedPoints.length === 0) {
|
||||
return {
|
||||
position: newPosition,
|
||||
isSnapped: false,
|
||||
snapSources: []
|
||||
};
|
||||
}
|
||||
|
||||
const newPos = new THREE.Vector3(...newPosition);
|
||||
let closestX: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
let closestZ: { pos: THREE.Vector3, dist: number } | null = null;
|
||||
|
||||
for (const connectedPoint of connectedPoints) {
|
||||
const cPos = new THREE.Vector3(...connectedPoint.position);
|
||||
|
||||
const xDist = Math.abs(newPos.x - cPos.x);
|
||||
const zDist = Math.abs(newPos.z - cPos.z);
|
||||
|
||||
if (xDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestX || xDist < closestX.dist) {
|
||||
closestX = { pos: cPos, dist: xDist };
|
||||
}
|
||||
}
|
||||
|
||||
if (zDist < ANGLE_SNAP_DISTANCE_THRESHOLD) {
|
||||
if (!closestZ || zDist < closestZ.dist) {
|
||||
closestZ = { pos: cPos, dist: zDist };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { position: position, isSnapped: false, snappedPoint: null };
|
||||
}, [currentPoint, getAllOtherWallPoints]);
|
||||
|
||||
const snappedPos = newPos.clone();
|
||||
const snapSources: THREE.Vector3[] = [];
|
||||
|
||||
if (closestX) {
|
||||
snappedPos.x = closestX.pos.x;
|
||||
snapSources.push(closestX.pos.clone());
|
||||
}
|
||||
|
||||
if (closestZ) {
|
||||
snappedPos.z = closestZ.pos.z;
|
||||
snapSources.push(closestZ.pos.clone());
|
||||
}
|
||||
|
||||
const isSnapped = snapSources.length > 0;
|
||||
|
||||
return {
|
||||
position: [snappedPos.x, snappedPos.y, snappedPos.z],
|
||||
isSnapped,
|
||||
snapSources
|
||||
};
|
||||
}, [currentPoint, getConnectedAislePoints]);
|
||||
|
||||
return {
|
||||
checkSnapForAisle,
|
||||
checkSnapForWall,
|
||||
snapAislePoint,
|
||||
snapAisleAngle,
|
||||
snapWallPoint,
|
||||
snapWallAngle,
|
||||
};
|
||||
};
|
||||
@@ -3,15 +3,15 @@ import * as Constants from '../../../types/world/worldConstants';
|
||||
import { useRef, useState, useEffect, useMemo } from 'react';
|
||||
import { useToolMode } from '../../../store/builder/store';
|
||||
import { DragControls } from '@react-three/drei';
|
||||
import { useAisleStore } from '../../../store/builder/useAisleStore';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { usePointSnapping } from './helpers/usePointSnapping';
|
||||
import { useAislePointSnapping } from './helpers/useAisleDragSnap';
|
||||
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';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
|
||||
function Point({ point }: { readonly point: Point }) {
|
||||
const materialRef = useRef<THREE.ShaderMaterial>(null);
|
||||
@@ -19,11 +19,13 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = useAisleStore();
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||
const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore();
|
||||
const { snapPosition } = useAislePointSnapping(point);
|
||||
const { checkSnapForAisle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
|
||||
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
|
||||
const colors = getColor(point);
|
||||
@@ -96,8 +98,8 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (point.pointType === 'Aisle') {
|
||||
if (position) {
|
||||
const newPosition: [number, number, number] = [position.x, position.y, position.z];
|
||||
const aisleSnappedPosition = snapPosition(newPosition);
|
||||
const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position);
|
||||
const aisleSnappedPosition = snapAisleAngle(newPosition);
|
||||
const finalSnappedPosition = snapAislePoint(aisleSnappedPosition.position);
|
||||
|
||||
setAislePosition(point.pointUuid, finalSnappedPosition.position);
|
||||
|
||||
@@ -105,8 +107,10 @@ function Point({ point }: { readonly point: Point }) {
|
||||
} else if (point.pointType === 'Wall') {
|
||||
if (position) {
|
||||
const newPosition: [number, number, number] = [position.x, position.y, position.z];
|
||||
const wallSnappedPosition = snapWallAngle(newPosition);
|
||||
const finalSnappedPosition = snapWallPoint(wallSnappedPosition.position);
|
||||
|
||||
setWallPosition(point.pointUuid, newPosition);
|
||||
setWallPosition(point.pointUuid, finalSnappedPosition.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +122,7 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||
if (updatedAisles.length > 0 && projectId) {
|
||||
updatedAisles.forEach((updatedAisle) => {
|
||||
createAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId)
|
||||
createAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '')
|
||||
})
|
||||
}
|
||||
} else if (point.pointType === 'Wall') {
|
||||
@@ -133,7 +137,7 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (removedAisles.length > 0) {
|
||||
removedAisles.forEach(aisle => {
|
||||
if (projectId)
|
||||
deleteAisleApi(aisle.aisleUuid, projectId)
|
||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '')
|
||||
});
|
||||
setHoveredPoint(null);
|
||||
}
|
||||
@@ -179,7 +183,7 @@ function Point({ point }: { readonly point: Point }) {
|
||||
}
|
||||
}}
|
||||
onPointerOut={() => {
|
||||
if (hoveredPoint && hoveredPoint.pointUuid === point.pointUuid) {
|
||||
if (hoveredPoint) {
|
||||
setHoveredPoint(null);
|
||||
}
|
||||
setIsHovered(false)
|
||||
|
||||
37
app/src/modules/builder/version/versionContext.tsx
Normal file
37
app/src/modules/builder/version/versionContext.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createContext, useContext, useMemo } from 'react';
|
||||
import { createSelectedVersionStore, SelectedVersionType } from '../../../store/simulation/useSimulationStore';
|
||||
|
||||
type VersionContextValue = {
|
||||
selectedVersionStore: SelectedVersionType,
|
||||
};
|
||||
|
||||
const VersionContext = createContext<VersionContextValue | null>(null);
|
||||
|
||||
export function VersionProvider({
|
||||
children,
|
||||
}: {
|
||||
readonly children: React.ReactNode;
|
||||
}) {
|
||||
const selectedVersionStore = useMemo(() => createSelectedVersionStore(), []);
|
||||
|
||||
const contextValue = useMemo(() => (
|
||||
{
|
||||
selectedVersionStore
|
||||
}
|
||||
), [selectedVersionStore]);
|
||||
|
||||
return (
|
||||
<VersionContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</VersionContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
// Base hook to get the context
|
||||
export function useVersionContext() {
|
||||
const context = useContext(VersionContext);
|
||||
if (!context) {
|
||||
throw new Error('useVersionContext must be used within a VersionProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -2,218 +2,131 @@ import { useMemo } from 'react';
|
||||
import * as turf from '@turf/turf';
|
||||
|
||||
export function useWallClassification(walls: Walls) {
|
||||
// Find all minimal rooms from the given walls
|
||||
|
||||
const findRooms = () => {
|
||||
if (walls.length < 3) return [];
|
||||
|
||||
// Build a graph of point connections
|
||||
const graph = new Map<string, string[]>();
|
||||
const pointMap = new Map<string, Point>();
|
||||
// Map pointUuid to list of connected line segments
|
||||
const pointMap = new Map<string, Wall[]>();
|
||||
|
||||
walls.forEach(wall => {
|
||||
const [p1, p2] = wall.points;
|
||||
pointMap.set(p1.pointUuid, p1);
|
||||
pointMap.set(p2.pointUuid, p2);
|
||||
for (const wall of walls) {
|
||||
for (const point of wall.points) {
|
||||
const list = pointMap.get(point.pointUuid) || [];
|
||||
list.push(wall);
|
||||
pointMap.set(point.pointUuid, list);
|
||||
}
|
||||
}
|
||||
|
||||
// Add connection from p1 to p2
|
||||
if (!graph.has(p1.pointUuid)) graph.set(p1.pointUuid, []);
|
||||
graph.get(p1.pointUuid)?.push(p2.pointUuid);
|
||||
// Create graph of connected walls using pointUuid
|
||||
const visited = new Set<string>();
|
||||
const mergedLineStrings = [];
|
||||
|
||||
// Add connection from p2 to p1
|
||||
if (!graph.has(p2.pointUuid)) graph.set(p2.pointUuid, []);
|
||||
graph.get(p2.pointUuid)?.push(p1.pointUuid);
|
||||
const wallKey = (p1: Point, p2: Point) => `${p1.pointUuid}-${p2.pointUuid}`;
|
||||
|
||||
for (const wall of walls) {
|
||||
const key = wallKey(wall.points[0], wall.points[1]);
|
||||
if (visited.has(key) || visited.has(wallKey(wall.points[1], wall.points[0]))) continue;
|
||||
|
||||
let line: Point[] = [...wall.points];
|
||||
visited.add(key);
|
||||
|
||||
// Try to extend the line forward and backward by matching endpoints
|
||||
let extended = true;
|
||||
while (extended) {
|
||||
extended = false;
|
||||
|
||||
const last = line[line.length - 1];
|
||||
const nextWalls = pointMap.get(last.pointUuid) || [];
|
||||
|
||||
for (const next of nextWalls) {
|
||||
const [n1, n2] = next.points;
|
||||
const nextKey = wallKey(n1, n2);
|
||||
if (visited.has(nextKey) || visited.has(wallKey(n2, n1))) continue;
|
||||
|
||||
if (n1.pointUuid === last.pointUuid && n2.pointUuid !== line[line.length - 2]?.pointUuid) {
|
||||
line.push(n2);
|
||||
visited.add(nextKey);
|
||||
extended = true;
|
||||
break;
|
||||
} else if (n2.pointUuid === last.pointUuid && n1.pointUuid !== line[line.length - 2]?.pointUuid) {
|
||||
line.push(n1);
|
||||
visited.add(nextKey);
|
||||
extended = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const first = line[0];
|
||||
const prevWalls = pointMap.get(first.pointUuid) || [];
|
||||
|
||||
for (const prev of prevWalls) {
|
||||
const [p1, p2] = prev.points;
|
||||
const prevKey = wallKey(p1, p2);
|
||||
if (visited.has(prevKey) || visited.has(wallKey(p2, p1))) continue;
|
||||
|
||||
if (p1.pointUuid === first.pointUuid && p2.pointUuid !== line[1]?.pointUuid) {
|
||||
line.unshift(p2);
|
||||
visited.add(prevKey);
|
||||
extended = true;
|
||||
break;
|
||||
} else if (p2.pointUuid === first.pointUuid && p1.pointUuid !== line[1]?.pointUuid) {
|
||||
line.unshift(p1);
|
||||
visited.add(prevKey);
|
||||
extended = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create merged LineString
|
||||
const coords = line.map(p => [p.position[0], p.position[2]]);
|
||||
mergedLineStrings.push(turf.lineString(coords, {
|
||||
pointUuids: line.map(p => p.pointUuid)
|
||||
}));
|
||||
}
|
||||
|
||||
const lineStrings = turf.featureCollection(mergedLineStrings);
|
||||
|
||||
// Now polygonize merged line strings
|
||||
const polygons = turf.polygonize(lineStrings);
|
||||
|
||||
const rooms: Point[][] = [];
|
||||
|
||||
polygons.features.forEach(feature => {
|
||||
if (feature.geometry.type === 'Polygon') {
|
||||
const coordinates = feature.geometry.coordinates[0];
|
||||
const roomPoints: Point[] = [];
|
||||
|
||||
for (const [x, z] of coordinates) {
|
||||
const matchingPoint = walls.flatMap(wall => wall.points)
|
||||
.find(p =>
|
||||
p.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
p.position[2].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
|
||||
if (matchingPoint) {
|
||||
roomPoints.push(matchingPoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (roomPoints.length > 0 &&
|
||||
roomPoints[0].pointUuid !== roomPoints[roomPoints.length - 1].pointUuid) {
|
||||
roomPoints.push(roomPoints[0]);
|
||||
}
|
||||
|
||||
if (roomPoints.length >= 4) {
|
||||
rooms.push(roomPoints);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Find all minimal cycles (rooms) in the graph
|
||||
const allCycles: string[][] = [];
|
||||
|
||||
const findCycles = (startNode: string, currentNode: string, path: string[], depth = 0) => {
|
||||
if (depth > 20) return; // Prevent infinite recursion
|
||||
|
||||
path.push(currentNode);
|
||||
|
||||
const neighbors = graph.get(currentNode) || [];
|
||||
|
||||
for (const neighbor of neighbors) {
|
||||
if (path.length > 2 && neighbor === startNode) {
|
||||
// Found a cycle that returns to start
|
||||
const cycle = [...path, neighbor];
|
||||
|
||||
// Check if this is a new unique cycle
|
||||
if (!cycleExists(allCycles, cycle)) {
|
||||
allCycles.push(cycle);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!path.includes(neighbor)) {
|
||||
findCycles(startNode, neighbor, [...path], depth + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start cycle detection from each node
|
||||
for (const [pointUuid] of graph) {
|
||||
findCycles(pointUuid, pointUuid, []);
|
||||
}
|
||||
|
||||
// Convert cycles to Point arrays and validate them
|
||||
const potentialRooms = allCycles
|
||||
.map(cycle => cycle.map(uuid => pointMap.get(uuid)!))
|
||||
.filter(room => isValidRoom(room));
|
||||
|
||||
const uniqueRooms = removeDuplicateRooms(potentialRooms);
|
||||
|
||||
// ✅ New logic that only removes redundant supersets
|
||||
const filteredRooms = removeSupersetLikeRooms(uniqueRooms, walls);
|
||||
|
||||
return filteredRooms;
|
||||
|
||||
console.log('rooms: ', rooms);
|
||||
return rooms;
|
||||
};
|
||||
|
||||
const removeSupersetLikeRooms = (rooms: Point[][], walls: Wall[]): Point[][] => {
|
||||
const toRemove = new Set<number>();
|
||||
|
||||
const getPolygon = (points: Point[]) =>
|
||||
turf.polygon([points.map(p => [p.position[0], p.position[2]])]);
|
||||
|
||||
const getWallSet = (room: Point[]) => {
|
||||
const set = new Set<string>();
|
||||
for (let i = 0; i < room.length - 1; i++) {
|
||||
const p1 = room[i].pointUuid;
|
||||
const p2 = room[i + 1].pointUuid;
|
||||
|
||||
const wall = walls.find(w =>
|
||||
(w.points[0].pointUuid === p1 && w.points[1].pointUuid === p2) ||
|
||||
(w.points[0].pointUuid === p2 && w.points[1].pointUuid === p1)
|
||||
);
|
||||
|
||||
if (wall) {
|
||||
set.add(wall.wallUuid);
|
||||
}
|
||||
}
|
||||
return set;
|
||||
};
|
||||
|
||||
const roomPolygons = rooms.map(getPolygon);
|
||||
const roomAreas = roomPolygons.map(poly => turf.area(poly));
|
||||
const wallSets = rooms.map(getWallSet);
|
||||
|
||||
// First, identify all rooms that are completely contained within others
|
||||
for (let i = 0; i < rooms.length; i++) {
|
||||
for (let j = 0; j < rooms.length; j++) {
|
||||
if (i === j) continue;
|
||||
|
||||
// If room i completely contains room j
|
||||
if (turf.booleanContains(roomPolygons[i], roomPolygons[j])) {
|
||||
// Check if the contained room shares most of its walls with the containing room
|
||||
const sharedWalls = [...wallSets[j]].filter(w => wallSets[i].has(w));
|
||||
const shareRatio = sharedWalls.length / wallSets[j].size;
|
||||
|
||||
// If they share more than 50% of walls, mark the larger one for removal
|
||||
// UNLESS the smaller one is significantly smaller (likely a real room)
|
||||
if (shareRatio > 0.5 && (roomAreas[i] / roomAreas[j] > 2)) {
|
||||
toRemove.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: handle cases where a room is divided by segmented walls
|
||||
for (let i = 0; i < rooms.length; i++) {
|
||||
if (toRemove.has(i)) continue;
|
||||
|
||||
for (let j = 0; j < rooms.length; j++) {
|
||||
if (i === j || toRemove.has(j)) continue;
|
||||
|
||||
// Check if these rooms share a significant portion of walls
|
||||
const sharedWalls = [...wallSets[i]].filter(w => wallSets[j].has(w));
|
||||
const shareRatio = Math.max(
|
||||
sharedWalls.length / wallSets[i].size,
|
||||
sharedWalls.length / wallSets[j].size
|
||||
);
|
||||
|
||||
// If they share more than 30% of walls and one is much larger
|
||||
if (shareRatio > 0.3) {
|
||||
const areaRatio = roomAreas[i] / roomAreas[j];
|
||||
if (areaRatio > 2) {
|
||||
// The larger room is likely the undivided version
|
||||
toRemove.add(i);
|
||||
} else if (areaRatio < 0.5) {
|
||||
// The smaller room might be an artifact
|
||||
toRemove.add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rooms.filter((_, idx) => !toRemove.has(idx));
|
||||
};
|
||||
|
||||
// Check if a cycle already exists in our list (considering different orders)
|
||||
const cycleExists = (allCycles: string[][], newCycle: string[]) => {
|
||||
const newSet = new Set(newCycle);
|
||||
|
||||
return allCycles.some(existingCycle => {
|
||||
if (existingCycle.length !== newCycle.length) return false;
|
||||
const existingSet = new Set(existingCycle);
|
||||
return setsEqual(newSet, existingSet);
|
||||
});
|
||||
};
|
||||
|
||||
// Check if two sets are equal
|
||||
const setsEqual = <T,>(a: Set<T>, b: Set<T>) => {
|
||||
if (a.size !== b.size) return false;
|
||||
for (const item of a) if (!b.has(item)) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Remove duplicate rooms (same set of points in different orders)
|
||||
const removeDuplicateRooms = (rooms: Point[][]) => {
|
||||
const uniqueRooms: Point[][] = [];
|
||||
const roomHashes = new Set<string>();
|
||||
|
||||
for (const room of rooms) {
|
||||
// Create a consistent hash for the room regardless of point order
|
||||
const hash = room
|
||||
.map(p => p.pointUuid)
|
||||
.sort()
|
||||
.join('-');
|
||||
|
||||
if (!roomHashes.has(hash)) {
|
||||
roomHashes.add(hash);
|
||||
uniqueRooms.push(room);
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueRooms;
|
||||
};
|
||||
|
||||
// Check if a room is valid (closed, non-self-intersecting polygon)
|
||||
const isValidRoom = (points: Point[]): boolean => {
|
||||
// Must have at least 4 points (first and last are same)
|
||||
if (points.length < 4) return false;
|
||||
|
||||
// Must be a closed loop
|
||||
if (points[0].pointUuid !== points[points.length - 1].pointUuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const coordinates = points.map(p => [p.position[0], p.position[2]]);
|
||||
const polygon = turf.polygon([coordinates]);
|
||||
return turf.booleanValid(polygon);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Rest of the implementation remains the same...
|
||||
const rooms = useMemo(() => findRooms(), [walls]);
|
||||
|
||||
// Determine wall orientation relative to room
|
||||
const findWallType = (wall: Wall) => {
|
||||
// Find all rooms that contain this wall
|
||||
const containingRooms = rooms.filter(room => {
|
||||
for (let i = 0; i < room.length - 1; i++) {
|
||||
const p1 = room[i];
|
||||
@@ -244,11 +157,7 @@ export function useWallClassification(walls: Walls) {
|
||||
}
|
||||
};
|
||||
|
||||
// Update the other functions to use the new return type
|
||||
const getWallType = (wall: Wall): {
|
||||
type: string;
|
||||
rooms: Point[][];
|
||||
} => {
|
||||
const getWallType = (wall: Wall) => {
|
||||
return findWallType(wall);
|
||||
};
|
||||
|
||||
@@ -261,11 +170,32 @@ export function useWallClassification(walls: Walls) {
|
||||
return findWallType(wall).type === 'segment';
|
||||
};
|
||||
|
||||
const isWallFlipped = (wall: Wall): boolean => {
|
||||
const wallType = findWallType(wall);
|
||||
if (wallType.type === 'segment') return false;
|
||||
|
||||
for (const room of wallType.rooms) {
|
||||
for (let i = 0; i < room.length - 1; i++) {
|
||||
const p1 = room[i];
|
||||
const p2 = room[i + 1];
|
||||
if (wall.points[0].pointUuid === p1.pointUuid && wall.points[1].pointUuid === p2.pointUuid) {
|
||||
return false;
|
||||
}
|
||||
if (wall.points[0].pointUuid === p2.pointUuid && wall.points[1].pointUuid === p1.pointUuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
rooms,
|
||||
getWallType,
|
||||
isRoomWall,
|
||||
isSegmentWall,
|
||||
findRooms,
|
||||
isWallFlipped
|
||||
};
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
function useWallGeometry(wallLength: number, wallHeight: number, wallThickness: number) {
|
||||
return useMemo(() => {
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
|
||||
const halfLength = wallLength / 2;
|
||||
const halfThickness = wallThickness / 2;
|
||||
const height = wallHeight;
|
||||
|
||||
const vertices = [
|
||||
-halfLength, -height / 2, halfThickness,
|
||||
-halfLength, height / 2, halfThickness,
|
||||
halfLength, height / 2, halfThickness,
|
||||
halfLength, -height / 2, halfThickness,
|
||||
-halfLength, -height / 2, -halfThickness,
|
||||
-halfLength, height / 2, -halfThickness,
|
||||
halfLength, height / 2, -halfThickness,
|
||||
halfLength, -height / 2, -halfThickness,
|
||||
-halfLength, height / 2, halfThickness,
|
||||
-halfLength, height / 2, -halfThickness,
|
||||
halfLength, height / 2, -halfThickness,
|
||||
halfLength, height / 2, halfThickness,
|
||||
-halfLength, -height / 2, halfThickness,
|
||||
-halfLength, -height / 2, -halfThickness,
|
||||
halfLength, -height / 2, -halfThickness,
|
||||
halfLength, -height / 2, halfThickness,
|
||||
];
|
||||
|
||||
const indices = [
|
||||
0, 1, 2, 0, 2, 3,
|
||||
4, 6, 5, 4, 7, 6,
|
||||
0, 4, 5, 0, 5, 1,
|
||||
3, 2, 6, 3, 6, 7,
|
||||
8, 9, 10, 8, 10, 11,
|
||||
12, 14, 13, 12, 15, 14
|
||||
];
|
||||
|
||||
geometry.setIndex(indices);
|
||||
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
|
||||
geometry.setAttribute('uv', new THREE.Float32BufferAttribute([
|
||||
0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0
|
||||
], 2));
|
||||
|
||||
geometry.computeVertexNormals();
|
||||
|
||||
geometry.addGroup(0, 6, 0); // Front
|
||||
geometry.addGroup(6, 6, 1); // Back
|
||||
geometry.addGroup(12, 6, 2); // Left
|
||||
geometry.addGroup(18, 6, 3); // Right
|
||||
geometry.addGroup(24, 6, 4); // Top
|
||||
geometry.addGroup(30, 6, 5); // Bottom
|
||||
|
||||
return geometry;
|
||||
}, [wallLength, wallHeight, wallThickness]);
|
||||
}
|
||||
|
||||
export default useWallGeometry;
|
||||
@@ -2,26 +2,29 @@ import * as THREE from 'three';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import * as Constants from '../../../../../types/world/worldConstants';
|
||||
|
||||
import insideMaterial from '../../../../../assets/textures/floor/wall-tex.png';
|
||||
import outsideMaterial from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
import useWallGeometry from './helpers/useWallGeometry';
|
||||
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 { 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 { Decal, PivotControls } from '@react-three/drei';
|
||||
import { Base, Geometry, Subtraction } from '@react-three/csg';
|
||||
|
||||
function Wall({ wall }: { readonly wall: Wall }) {
|
||||
const { walls } = useWallStore();
|
||||
const { getWallType } = useWallClassification(walls);
|
||||
const { getWallType, isWallFlipped } = useWallClassification(walls);
|
||||
const wallType = getWallType(wall);
|
||||
const [startPoint, endPoint] = wall.points;
|
||||
const [visible, setVisible] = useState(true);
|
||||
const { wallVisibility } = useWallVisibility();
|
||||
const meshRef = useRef<any>();
|
||||
const { camera } = useThree();
|
||||
|
||||
const wallFlipped = isWallFlipped(wall);
|
||||
|
||||
const [rawStart, rawEnd] = wall.points;
|
||||
const [startPoint, endPoint] = wallFlipped ? [rawStart, rawEnd] : [rawEnd, rawStart];
|
||||
|
||||
const startX = startPoint.position[0];
|
||||
const startZ = startPoint.position[2];
|
||||
const endX = endPoint.position[0];
|
||||
@@ -36,13 +39,13 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
const [insideWallTexture, outsideWallTexture] = useMemo(() => {
|
||||
const inside = textureLoader.load(insideMaterial);
|
||||
const [defaultWallTexture, material1WallTexture] = useMemo(() => {
|
||||
const inside = textureLoader.load(defaultMaterial);
|
||||
inside.wrapS = inside.wrapT = THREE.RepeatWrapping;
|
||||
inside.repeat.set(wallLength / 10, wall.wallHeight / 10);
|
||||
inside.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
const outside = textureLoader.load(outsideMaterial);
|
||||
const outside = textureLoader.load(material1);
|
||||
outside.wrapS = outside.wrapT = THREE.RepeatWrapping;
|
||||
outside.repeat.set(wallLength / 10, wall.wallHeight / 10);
|
||||
outside.colorSpace = THREE.SRGBColorSpace;
|
||||
@@ -51,29 +54,25 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
}, [wallLength, wall.wallHeight]);
|
||||
|
||||
const materials = useMemo(() => {
|
||||
const frontMaterial = insideWallTexture;
|
||||
|
||||
const backMaterial = outsideWallTexture;
|
||||
|
||||
return [
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible }), // Left
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible }), // Right
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible }), // Top
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, visible: visible }), // Bottom
|
||||
new THREE.MeshStandardMaterial({
|
||||
color: Constants.wallConfig.defaultColor,
|
||||
side: THREE.DoubleSide,
|
||||
map: frontMaterial
|
||||
map: wall.insideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture,
|
||||
}),
|
||||
new THREE.MeshStandardMaterial({
|
||||
color: Constants.wallConfig.defaultColor,
|
||||
side: THREE.DoubleSide,
|
||||
map: backMaterial
|
||||
map: wall.outsideMaterial === 'Default Material`' ? defaultWallTexture : material1WallTexture,
|
||||
}),
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Left
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Right
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }), // Top
|
||||
new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide }) // Bottom
|
||||
];
|
||||
}, [insideWallTexture, outsideWallTexture, wall]);
|
||||
}, [defaultWallTexture, material1WallTexture, wall]);
|
||||
|
||||
const geometry = useWallGeometry(wallLength, wall.wallHeight, wall.wallThickness);
|
||||
const geometry = useMemo(() => new THREE.BoxGeometry(wallLength, wall.wallHeight, wall.wallThickness), [wallLength, wall.wallHeight, wall.wallThickness]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!meshRef.current) return;
|
||||
@@ -83,6 +82,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
if (!wallVisibility && wallType.type === 'room') {
|
||||
meshRef.current.getWorldDirection(v);
|
||||
camera.getWorldDirection(u);
|
||||
if (!u || !v) return;
|
||||
setVisible((2 * v.dot(u)) <= 0.1);
|
||||
|
||||
} else {
|
||||
@@ -91,16 +91,19 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
})
|
||||
|
||||
return (
|
||||
<group
|
||||
<mesh
|
||||
name={`Wall-${wall.wallUuid}`}
|
||||
key={wall.wallUuid}
|
||||
userData={wall}
|
||||
position={[centerX, centerY, centerZ]}
|
||||
rotation={[0, -angle, 0]}
|
||||
visible={visible}
|
||||
>
|
||||
<Base ref={meshRef} geometry={geometry} visible>
|
||||
<Base
|
||||
ref={meshRef}
|
||||
geometry={geometry}
|
||||
position={[centerX, centerY, centerZ]}
|
||||
rotation={[0, -angle, 0]}
|
||||
>
|
||||
{materials.map((material, index) => (
|
||||
<primitive key={index} object={material} attach={`material-${index}`} />
|
||||
<primitive key={index} visible={visible} object={material} attach={`material-${index}`} />
|
||||
))}
|
||||
|
||||
{wall.decals.map((decal) => {
|
||||
@@ -112,7 +115,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
scale={[decal.decalScale, decal.decalScale, 0.001]}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
map={outsideWallTexture}
|
||||
map={material1WallTexture}
|
||||
side={THREE.DoubleSide}
|
||||
polygonOffset
|
||||
polygonOffsetFactor={-1}
|
||||
@@ -121,7 +124,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
)
|
||||
})}
|
||||
</Base>
|
||||
</group>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,11 @@ import WallInstance from './instance/wallInstance';
|
||||
import Line from '../../line/line';
|
||||
import Point from '../../point/point';
|
||||
import { useToggleView } from '../../../../store/builder/store';
|
||||
import { Base, Geometry, Subtraction } from '@react-three/csg';
|
||||
import { BoxGeometry } from 'three';
|
||||
import { Geometry } from '@react-three/csg';
|
||||
|
||||
function WallInstances() {
|
||||
const { walls } = useWallStore();
|
||||
const { toggleView } = useToggleView();
|
||||
const ref = useRef<any>();
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('walls: ', walls);
|
||||
@@ -34,26 +32,25 @@ function WallInstances() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<group name='Walls-Group' ref={ref}>
|
||||
<Geometry computeVertexNormals>
|
||||
|
||||
{walls.map((wall) => (
|
||||
<WallInstance key={wall.wallUuid} wall={wall} />
|
||||
))}
|
||||
{!toggleView && (
|
||||
|
||||
{/* <Base geometry={new BoxGeometry()} >
|
||||
<meshStandardMaterial />
|
||||
</Base>
|
||||
<mesh name='Walls-Group'>
|
||||
{/* <Base name="base" geometry={box} scale={[3, 3, 3]} /> */}
|
||||
|
||||
<Geometry>
|
||||
<Subtraction scale={[5, 11, 5]} >
|
||||
<Geometry>
|
||||
<Base geometry={new BoxGeometry()} />
|
||||
</Geometry>
|
||||
</Subtraction>
|
||||
</Geometry> */}
|
||||
</Geometry>
|
||||
</group>
|
||||
<Geometry useGroups>
|
||||
{walls.map((wall) => (
|
||||
<WallInstance key={wall.wallUuid} wall={wall} />
|
||||
))}
|
||||
</Geometry>
|
||||
|
||||
{/* <Subtraction rotation={[0, Math.PI / 2, 0]} position={[-1.425, -0.45, 0]} scale={[1, 3, 1]}>
|
||||
<Geometry>
|
||||
<Base geometry={box} />
|
||||
</Geometry>
|
||||
</Subtraction> */}
|
||||
</mesh>
|
||||
)}
|
||||
|
||||
{toggleView && (
|
||||
<>
|
||||
@@ -76,4 +73,4 @@ function WallInstances() {
|
||||
)
|
||||
}
|
||||
|
||||
export default WallInstances
|
||||
export default WallInstances
|
||||
|
||||
@@ -26,7 +26,7 @@ function ReferenceWall({ tempPoints }: Readonly<ReferenceWallProps>) {
|
||||
const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);
|
||||
|
||||
const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[0]?.position || null);
|
||||
const { checkSnapForWall } = usePointSnapping({ uuid: 'temp-wall', pointType: 'Wall', position: directionalSnap.position || [0, 0, 0] });
|
||||
const { snapWallPoint } = usePointSnapping({ uuid: 'temp-wall', pointType: 'Wall', position: directionalSnap.position || [0, 0, 0] });
|
||||
|
||||
useFrame(() => {
|
||||
if (toolMode === 'Wall' && toggleView && tempPoints.length === 1) {
|
||||
@@ -37,7 +37,7 @@ function ReferenceWall({ tempPoints }: Readonly<ReferenceWallProps>) {
|
||||
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
|
||||
if (intersectionPoint) {
|
||||
const snapped = checkSnapForWall([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
const snapped = snapWallPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
|
||||
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||
finalPosition.current = snapped.position;
|
||||
@@ -68,8 +68,8 @@ function ReferenceWall({ tempPoints }: Readonly<ReferenceWallProps>) {
|
||||
setTempWall({
|
||||
wallUuid: 'temp-wall',
|
||||
points: wallPoints,
|
||||
outSideMaterial: 'default',
|
||||
inSideMaterial: 'default',
|
||||
outsideMaterial: 'default',
|
||||
insideMaterial: 'default',
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
|
||||
@@ -2,10 +2,12 @@ import * as THREE from 'three'
|
||||
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 { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceWall from './referenceWall';
|
||||
import getClosestIntersection from '../../geomentries/lines/getClosestIntersection';
|
||||
|
||||
function WallCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -14,10 +16,10 @@ function WallCreator() {
|
||||
const { toolMode } = useToolMode();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { socket } = useSocketStore();
|
||||
const { addWall, getWallPointById } = useWallStore();
|
||||
const { addWall, getWallPointById, removeWall, getWallByPoints } = useWallStore();
|
||||
const drag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const { wallThickness, wallHeight, snappedPosition, snappedPoint } = useBuilderStore();
|
||||
const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore();
|
||||
|
||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
@@ -52,7 +54,118 @@ function WallCreator() {
|
||||
let position = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||
if (!position) return;
|
||||
|
||||
const intersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Point');
|
||||
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Point');
|
||||
|
||||
const wallIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Wall-Line');
|
||||
if (wallIntersect && !pointIntersects) {
|
||||
const wall = getWallByPoints(wallIntersect.object.userData.points);
|
||||
if (wall) {
|
||||
const ThroughPoint = wallIntersect.object.userData.path.getPoints(Constants.lineConfig.lineIntersectionPoints);
|
||||
let intersectionPoint = getClosestIntersection(ThroughPoint, wallIntersect.point);
|
||||
const point1Vec = new THREE.Vector3(...wall.points[0].position);
|
||||
const point2Vec = new THREE.Vector3(...wall.points[1].position);
|
||||
|
||||
const lineDir = new THREE.Vector3().subVectors(point2Vec, point1Vec).normalize();
|
||||
|
||||
const point1ToIntersect = new THREE.Vector3().subVectors(intersectionPoint, point1Vec);
|
||||
|
||||
const dotProduct = point1ToIntersect.dot(lineDir);
|
||||
const projection = new THREE.Vector3().copy(lineDir).multiplyScalar(dotProduct).add(point1Vec);
|
||||
|
||||
const lineLength = point1Vec.distanceTo(point2Vec);
|
||||
let t = point1Vec.distanceTo(projection) / lineLength;
|
||||
t = Math.max(0, Math.min(1, t));
|
||||
|
||||
const closestPoint = new THREE.Vector3().lerpVectors(point1Vec, point2Vec, t);
|
||||
|
||||
removeWall(wall.wallUuid);
|
||||
|
||||
const point1: Point = {
|
||||
pointUuid: wall.points[0].pointUuid,
|
||||
pointType: 'Wall',
|
||||
position: wall.points[0].position,
|
||||
layer: wall.points[0].layer
|
||||
};
|
||||
|
||||
const point2: Point = {
|
||||
pointUuid: wall.points[1].pointUuid,
|
||||
pointType: 'Wall',
|
||||
position: wall.points[1].position,
|
||||
layer: wall.points[1].layer
|
||||
};
|
||||
|
||||
const newPoint: Point = {
|
||||
pointUuid: THREE.MathUtils.generateUUID(),
|
||||
pointType: 'Wall',
|
||||
position: closestPoint.toArray(),
|
||||
layer: activeLayer
|
||||
};
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
const wall2: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point1, newPoint],
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
}
|
||||
addWall(wall2);
|
||||
|
||||
const wall3: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point2, newPoint],
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
}
|
||||
addWall(wall3);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const wall1: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
};
|
||||
addWall(wall1);
|
||||
|
||||
const wall2: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point1, newPoint],
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
}
|
||||
addWall(wall2);
|
||||
|
||||
const wall3: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point2, newPoint],
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
}
|
||||
addWall(wall3);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const newPoint: Point = {
|
||||
pointUuid: THREE.MathUtils.generateUUID(),
|
||||
@@ -71,8 +184,8 @@ function WallCreator() {
|
||||
newPoint.position = snappedPosition;
|
||||
}
|
||||
|
||||
if (intersects && !snappedPoint) {
|
||||
const point = getWallPointById(intersects.object.uuid);
|
||||
if (pointIntersects && !snappedPoint) {
|
||||
const point = getWallPointById(pointIntersects.object.uuid);
|
||||
if (point) {
|
||||
newPoint.pointUuid = point.pointUuid;
|
||||
newPoint.position = point.position;
|
||||
@@ -87,8 +200,8 @@ function WallCreator() {
|
||||
const wall: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
outSideMaterial: 'default',
|
||||
inSideMaterial: 'default',
|
||||
outsideMaterial: insideMaterial,
|
||||
insideMaterial: outsideMaterial,
|
||||
wallThickness: wallThickness,
|
||||
wallHeight: wallHeight,
|
||||
decals: []
|
||||
@@ -114,10 +227,8 @@ function WallCreator() {
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContext);
|
||||
} else {
|
||||
if (tempPoints.length > 0 || isCreating) {
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user