Compare commits
63 Commits
ui
...
dev-api-so
| Author | SHA1 | Date | |
|---|---|---|---|
| a3b2d258cf | |||
| 4bfd0cf937 | |||
| ae4fd2ff01 | |||
| d5d064b875 | |||
| cfc1f2dee8 | |||
| 0ac2bde6d3 | |||
| 1cef2987a6 | |||
| 0ab0510daf | |||
| 6f9da9e9c0 | |||
| 8e7c5a1aa0 | |||
| 765f4acb57 | |||
| ef98b3c1a3 | |||
| 09c909c377 | |||
| 7d7100893c | |||
| 9825c3ef12 | |||
| 3bc0e28267 | |||
| f9d314b69f | |||
| b956ed57e8 | |||
| df36ee0366 | |||
| ef9c3a9c63 | |||
| 62ddc1c25f | |||
| 1b161b2176 | |||
| a14f7fcf6a | |||
| b6783f99d3 | |||
| b2311ab186 | |||
| d915c643d1 | |||
| 363906aa12 | |||
| e23e339ed3 | |||
| 2ba418ab6c | |||
| 982a8ef4aa | |||
| e304614df5 | |||
| 7bbb221c66 | |||
| 94bec4f2f0 | |||
| cb87cd067b | |||
| 92b1ba6197 | |||
| 5ef383095a | |||
| c4d1f90ee7 | |||
| 8ff609b85c | |||
| d129a86885 | |||
| d4f12d230f | |||
| 441f1efb23 | |||
| 243fd6452c | |||
| c0e040fb3a | |||
| 165325468a | |||
| 98be35bf5f | |||
| 547fd1af12 | |||
| 0387d7a932 | |||
| bb2a27e2f9 | |||
| 06b6b3d0ce | |||
| b4b412ce14 | |||
| 1d2a42b7bd | |||
| 6fa4d5323d | |||
| ed099c7f75 | |||
| e813f194c7 | |||
| 2125c3dc73 | |||
| cd86846a37 | |||
| 6026c3b82b | |||
| 358ce22767 | |||
| ff22152d8c | |||
| 6aeef163d2 | |||
| 246236c15f | |||
| affffe09c8 | |||
| 67b942ac16 |
@@ -7,6 +7,7 @@ import UserAuth from "./pages/UserAuth";
|
||||
import "./styles/main.scss";
|
||||
import { LoggerProvider } from "./components/ui/log/LoggerContext";
|
||||
import ForgotPassword from "./pages/ForgotPassword";
|
||||
import PageNotFound from "./pages/PageNotFound";
|
||||
|
||||
const App: React.FC = () => {
|
||||
|
||||
@@ -23,6 +24,7 @@ const App: React.FC = () => {
|
||||
<Route path="/forgot" element={<ForgotPassword />} />
|
||||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/projects/:projectId" element={<Project />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</LoggerProvider>
|
||||
|
||||
9
app/src/assets/image/404/404.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="435" height="192" viewBox="0 0 435 192" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M434.294 35.8327L419.597 87.2712C406.577 88.0129 399.354 88.9272 386.529 90.946L393.877 59.3474L332.885 112.991L377.711 126.218L379.915 115.93C393.611 111.893 401.218 109.947 414.453 107.847L407.84 134.301L427.681 140.18L419.597 167.37L401.226 162.226L392.407 191.62L362.279 183.537L369.627 151.938L297.612 132.097L304.961 104.173L398.286 24.8093L434.294 35.8327Z" fill="#0F0F0F"/>
|
||||
<path d="M107.287 110.787L127.128 106.378L132.271 133.567L113.9 137.976L119.779 168.84L86.7109 176.923L80.833 144.59L63.9316 148.999C72.6686 121.327 81.38 109.098 102.144 91.6804L107.287 110.787Z" fill="#0F0F0F"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M204.287 0.55928C212.617 -0.162914 217.275 -0.209574 225.598 0.55928C254.396 3.22002 271.652 31.4235 274.832 50.529C276.587 61.0745 277.015 67.0381 277.037 77.7185C265.905 97.6708 263.444 104.779 252.787 126.218C243.954 141.438 233.146 152.429 218.249 162.226C186.397 160.022 167.896 140.12 157.991 109.317C154.89 92.6487 155.445 73.5003 156.521 59.3474C158.678 31.0003 174.892 6.89136 204.287 0.55928ZM217.147 23.9997C197.265 23.9997 181.147 48.624 181.147 78.9997C181.147 109.375 197.265 134 217.147 134C237.029 133.999 253.147 109.375 253.147 78.9997C253.147 48.6243 237.029 24.0001 217.147 23.9997Z" fill="#0F0F0F"/>
|
||||
<path d="M99.2041 71.1052L66.1357 81.3923L60.2568 50.529L29.3936 126.953L66.1357 120.34C58.6892 132.967 56.9985 139.297 54.3779 150.468L7.34766 160.757L0 131.362L49.2344 17.4606L85.2422 10.113L99.2041 71.1052Z" fill="#0F0F0F"/>
|
||||
<path d="M277.037 96.8249C275.203 113.08 274.273 122.314 268.953 134.301C257.417 152.202 250.176 154.67 237.354 160.021C254.909 142.239 264.111 127.901 277.037 96.8249Z" fill="#0F0F0F"/>
|
||||
<path d="M99.2041 81.3923C89.3926 88.8475 83.8084 94.1174 73.4844 109.317L68.3398 91.6804L99.2041 81.3923Z" fill="#0F0F0F"/>
|
||||
<path d="M383.59 100.499C397.029 98.1517 404.407 97.8166 417.393 98.2946C404.464 99.701 397.094 100.893 383.59 104.173V100.499Z" fill="#0F0F0F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/assets/image/404/404_bk.png
Normal file
|
After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
BIN
app/src/assets/image/fallback/fallback decal 1.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
app/src/assets/image/fallback/fallback decal.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useRef, useEffect, act } from "react";
|
||||
import React, { useState, useRef } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import img from "../../assets/image/image.png";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
@@ -7,11 +8,11 @@ import {
|
||||
useProjectName,
|
||||
useSocketStore,
|
||||
} from "../../store/builder/store";
|
||||
import { viewProject } from "../../services/dashboard/viewProject";
|
||||
import OuterClick from "../../utils/outerClick";
|
||||
import { KebabIcon } from "../icons/ExportCommonIcons";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { updateProject } from "../../services/dashboard/updateProject";
|
||||
// import { viewProject } from "../../services/dashboard/viewProject";
|
||||
// import { updateProject } from "../../services/dashboard/updateProject";
|
||||
|
||||
interface DashBoardCardProps {
|
||||
projectName: string;
|
||||
@@ -69,9 +70,9 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const navigateToProject = async (e: any) => {
|
||||
if (active && active == "trash") return;
|
||||
if (active && active === "trash") return;
|
||||
try {
|
||||
const viewProjects = await viewProject(organization, projectId, userId);
|
||||
// const viewProjects = await viewProject(organization, projectId, userId);
|
||||
|
||||
setLoadingProgress(1);
|
||||
setProjectName(projectName);
|
||||
@@ -96,13 +97,13 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
case "open in new tab":
|
||||
try {
|
||||
if (active === "shared" && createdBy) {
|
||||
const newTab = await viewProject(
|
||||
organization,
|
||||
projectId,
|
||||
createdBy?._id
|
||||
);
|
||||
// const newTab = await viewProject(
|
||||
// organization,
|
||||
// projectId,
|
||||
// createdBy?._id
|
||||
// );
|
||||
} else {
|
||||
const newTab = await viewProject(organization, projectId, userId);
|
||||
// const newTab = await viewProject(organization, projectId, userId);
|
||||
|
||||
setProjectName(projectName);
|
||||
setIsKebabOpen(false);
|
||||
@@ -226,7 +227,7 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
className="dashboard-card-container"
|
||||
onClick={navigateToProject}
|
||||
title={projectName}
|
||||
onMouseLeave={() => setIsKebabOpen(false)}
|
||||
// onMouseLeave={() => setIsKebabOpen(false)}
|
||||
>
|
||||
<div className="dashboard-card-wrapper">
|
||||
<div className="preview-container">
|
||||
@@ -267,7 +268,7 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
)}
|
||||
{createdAt && (
|
||||
<div className="project-data">
|
||||
{active && active == "trash" ? `Trashed by you` : `Edited `}{" "}
|
||||
{active && active === "trash" ? `Trashed by you` : `Edited `}{" "}
|
||||
{getRelativeTime(createdAt)}
|
||||
</div>
|
||||
)}
|
||||
@@ -292,22 +293,37 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isKebabOpen && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{getOptions().map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{isKebabOpen &&
|
||||
createPortal(
|
||||
<div
|
||||
className="kebab-options-wrapper"
|
||||
style={{
|
||||
position: "fixed",
|
||||
zIndex: 9999,
|
||||
top: kebabRef.current
|
||||
? kebabRef.current.getBoundingClientRect().bottom +
|
||||
window.scrollY
|
||||
: 0,
|
||||
left: kebabRef.current
|
||||
? kebabRef.current.getBoundingClientRect().left + window.scrollX
|
||||
: 0,
|
||||
}}
|
||||
>
|
||||
{getOptions().map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ const DashboardHome: React.FC = () => {
|
||||
if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) {
|
||||
setRecentProjects(projects);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
const handleRecentProjectSearch = async (inputValue: string) => {
|
||||
@@ -66,7 +66,7 @@ const DashboardHome: React.FC = () => {
|
||||
// );
|
||||
//
|
||||
|
||||
//socket for delete Project
|
||||
// SOCKET for delete Project
|
||||
const deleteProject = {
|
||||
projectId,
|
||||
organization,
|
||||
@@ -90,7 +90,7 @@ const DashboardHome: React.FC = () => {
|
||||
};
|
||||
});
|
||||
setIsSearchActive(false);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
const handleDuplicateRecentProject = async (
|
||||
@@ -98,15 +98,18 @@ const DashboardHome: React.FC = () => {
|
||||
projectName: string,
|
||||
thumbnail: string
|
||||
) => {
|
||||
const duplicateRecentProjectData = {
|
||||
userId,
|
||||
thumbnail,
|
||||
organization,
|
||||
projectUuid: generateUniqueId(),
|
||||
refProjectID: projectId,
|
||||
projectName,
|
||||
};
|
||||
projectSocket.emit("v1:project:Duplicate", duplicateRecentProjectData);
|
||||
if (projectSocket) {
|
||||
|
||||
const duplicateRecentProjectData = {
|
||||
userId,
|
||||
thumbnail,
|
||||
organization,
|
||||
projectUuid: generateUniqueId(),
|
||||
refProjectID: projectId,
|
||||
projectName,
|
||||
};
|
||||
projectSocket.emit("v1:project:Duplicate", duplicateRecentProjectData);
|
||||
}
|
||||
};
|
||||
|
||||
const renderProjects = () => {
|
||||
|
||||
@@ -60,7 +60,7 @@ const DashboardProjects: React.FC = () => {
|
||||
if (JSON.stringify(projects) !== JSON.stringify(workspaceProjects)) {
|
||||
setWorkspaceProjects(projects);
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
const handleDeleteProject = async (projectId: any) => {
|
||||
@@ -77,7 +77,7 @@ const DashboardProjects: React.FC = () => {
|
||||
userId,
|
||||
};
|
||||
|
||||
//socket for deleting the project
|
||||
// SOCKET for deleting the project
|
||||
if (projectSocket) {
|
||||
projectSocket.emit("v1:project:delete", deleteProjects);
|
||||
} else {
|
||||
@@ -95,7 +95,7 @@ const DashboardProjects: React.FC = () => {
|
||||
};
|
||||
});
|
||||
setIsSearchActive(false);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
const handleDuplicateWorkspaceProject = async (
|
||||
@@ -110,16 +110,17 @@ const DashboardProjects: React.FC = () => {
|
||||
// projectName
|
||||
// );
|
||||
// console.log("duplicatedProject: ", duplicatedProject);
|
||||
|
||||
const duplicateProjectData = {
|
||||
userId,
|
||||
thumbnail,
|
||||
organization,
|
||||
projectUuid: generateUniqueId(),
|
||||
refProjectID: projectId,
|
||||
projectName,
|
||||
};
|
||||
projectSocket.emit("v1:project:Duplicate", duplicateProjectData);
|
||||
if (projectSocket) {
|
||||
const duplicateProjectData = {
|
||||
userId,
|
||||
thumbnail,
|
||||
organization,
|
||||
projectUuid: generateUniqueId(),
|
||||
refProjectID: projectId,
|
||||
projectName,
|
||||
};
|
||||
projectSocket.emit("v1:project:Duplicate", duplicateProjectData);
|
||||
}
|
||||
};
|
||||
|
||||
const renderProjects = () => {
|
||||
@@ -166,7 +167,7 @@ const DashboardProjects: React.FC = () => {
|
||||
try {
|
||||
const sharedWithMe = await sharedWithMeProjects();
|
||||
setSharedWithMeProjects(sharedWithMe);
|
||||
} catch {}
|
||||
} catch { }
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -38,12 +38,13 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
const handleCreateNewProject = async () => {
|
||||
const token = localStorage.getItem("token");
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
console.log("refreshToken: ", refreshToken);
|
||||
if (!token || !refreshToken) {
|
||||
console.error('token expired');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const projectId = generateProjectId();
|
||||
useSocketStore
|
||||
.getState()
|
||||
.initializeSocket(email, organization, token, refreshToken);
|
||||
useSocketStore.getState().initializeSocket(email, organization, token, refreshToken);
|
||||
|
||||
//API for creating new Project
|
||||
// const project = await createProject(
|
||||
@@ -60,11 +61,10 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
projectUuid: projectId,
|
||||
};
|
||||
|
||||
console.log("projectSocket: ", projectSocket);
|
||||
if (projectSocket) {
|
||||
const handleResponse = (data: any) => {
|
||||
if (data.message === "Project created successfully") {
|
||||
setLoadingProgress(1)
|
||||
setLoadingProgress(1);
|
||||
navigate(`/projects/${data.data.projectId}`);
|
||||
}
|
||||
projectSocket.off("v1-project:response:add", handleResponse); // Clean up
|
||||
@@ -90,7 +90,7 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
<div className="user-name">
|
||||
{userName
|
||||
? userName.charAt(0).toUpperCase() +
|
||||
userName.slice(1).toLowerCase()
|
||||
userName.slice(1).toLowerCase()
|
||||
: "Anonymous"}
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,7 +141,10 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
activeTab === "Tutorials" ? "option-list active" : "option-list"
|
||||
}
|
||||
title="coming soon"
|
||||
onClick={() => setActiveTab("Tutorials")}
|
||||
onClick={() => {
|
||||
// setActiveTab("Tutorials");
|
||||
console.warn("Tutorials comming soon");
|
||||
}}
|
||||
>
|
||||
<TutorialsIcon />
|
||||
Tutorials
|
||||
@@ -153,14 +156,17 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
: "option-list"
|
||||
}
|
||||
title="coming soon"
|
||||
onClick={() => setActiveTab("Documentation")}
|
||||
onClick={() => {
|
||||
// setActiveTab("Documentation");
|
||||
console.warn("Documentation comming soon");
|
||||
}}
|
||||
>
|
||||
<DocumentationIcon />
|
||||
Documentation
|
||||
</div>
|
||||
</div>
|
||||
<div className="side-bar-options-container" title="coming soon">
|
||||
<div className="option-list">
|
||||
<div className="side-bar-options-container">
|
||||
<div className="option-list" title="coming soon">
|
||||
<SettingsIcon />
|
||||
Settings
|
||||
</div>
|
||||
@@ -175,7 +181,7 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
<LogoutIcon />
|
||||
Log out
|
||||
</div>
|
||||
<div className="option-list">
|
||||
<div className="option-list" title="coming soon">
|
||||
<HelpIcon />
|
||||
Help & Feedback
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { HelpIcon } from "../icons/DashboardIcon";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { HelpIcon, WifiIcon } from "../icons/DashboardIcon";
|
||||
import { useLogger } from "../ui/log/LoggerContext";
|
||||
import { GetLogIcon } from "./getLogIcons";
|
||||
import {
|
||||
@@ -31,6 +31,27 @@ const Footer: React.FC = () => {
|
||||
|
||||
const { Leftnote, Middlenote, Rightnote } = useMouseNoteStore();
|
||||
|
||||
const [isOnline, setIsOnline] = useState<boolean>(navigator.onLine);
|
||||
|
||||
useEffect(() => {
|
||||
const handleOnline = () => {
|
||||
echo.success('You are back Online');
|
||||
setIsOnline(true);
|
||||
};
|
||||
const handleOffline = () => {
|
||||
echo.warn('Changes made now might not be saved');
|
||||
echo.error('You are now Offline.');
|
||||
setIsOnline(false);
|
||||
};
|
||||
|
||||
window.addEventListener("online", handleOnline);
|
||||
window.addEventListener("offline", handleOffline);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("online", handleOnline);
|
||||
window.removeEventListener("offline", handleOffline);
|
||||
};
|
||||
}, []);
|
||||
const mouseButtons = [
|
||||
{
|
||||
icon: <CurserLeftIcon />,
|
||||
@@ -98,6 +119,16 @@ const Footer: React.FC = () => {
|
||||
<HelpIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`wifi-connection ${
|
||||
isOnline ? "connected" : "disconnected"
|
||||
}`}
|
||||
>
|
||||
<div className="icon">
|
||||
<WifiIcon />
|
||||
</div>
|
||||
<div className="tooltip">{isOnline ? "Online" : "Offline"}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
370
app/src/components/icons/AssetTypeIcons.tsx
Normal file
@@ -0,0 +1,370 @@
|
||||
export const ForkLiftIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_6014_655)">
|
||||
<g filter="url(#filter0_f_6014_655)">
|
||||
<path
|
||||
d="M4.97826 12.4473C4.1581 12.4473 3.49243 13.112 3.49243 13.9331C3.49243 14.753 4.15813 15.4177 4.97826 15.4177C5.79818 15.4177 6.46284 14.753 6.46284 13.9331C6.46284 13.1119 5.79815 12.4473 4.97826 12.4473ZM4.97826 14.4544C4.69055 14.4544 4.45567 14.2208 4.45567 13.9331C4.45567 13.6454 4.69052 13.4105 4.97826 13.4105C5.26573 13.4105 5.49957 13.6454 5.49957 13.9331C5.49957 14.2208 5.26573 14.4544 4.97826 14.4544Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.3257 5.81717C11.1156 5.08596 10.4467 4.58203 9.6857 4.58203H5.20523C4.84291 4.58203 4.5491 4.87583 4.5491 5.23816V9.41249H4.07715C3.26935 9.41249 2.6145 10.0673 2.6145 10.8751V13.4258H2.88458C3.11388 12.4815 3.96429 11.7774 4.9782 11.7774C5.99161 11.7774 6.84123 12.4815 7.07052 13.4258H8.05798C8.13812 12.1123 9.22862 11.0679 10.5618 11.0679C11.2884 11.0679 11.9421 11.3804 12.4009 11.876V11.7487V10.3279C12.4009 9.8179 12.3293 9.31021 12.1885 8.82012L11.3257 5.81717ZM10.1793 8.21563L9.49446 8.6286L10.5313 10.6025H8.67763L7.81739 9.41249H6.07579V5.66572H9.6857C9.96187 5.66572 10.208 5.85115 10.2844 6.1165L11.1471 9.11919C11.2058 9.32329 11.2487 9.53116 11.2769 9.74131L10.1793 8.21563Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M10.5616 11.7383C9.54538 11.7383 8.7207 12.5617 8.7207 13.5792C8.7207 14.5948 9.54538 15.4183 10.5616 15.4183C11.5772 15.4183 12.4007 14.5948 12.4007 13.5792C12.4007 12.5617 11.5772 11.7383 10.5616 11.7383ZM10.5616 14.225C10.2051 14.225 9.91402 13.9357 9.91402 13.5792C9.91402 13.2226 10.2051 12.9316 10.5616 12.9316C10.9176 12.9316 11.2074 13.2226 11.2074 13.5792C11.2074 13.9357 10.9176 14.225 10.5616 14.225Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M14.8484 14.1482C14.3396 14.1482 13.9269 13.7355 13.9269 13.2268V4.58203H12.7197V15.0314H18.679V14.1482H14.8484Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.85501 7.42463L8.88497 8.09259C8.78745 8.15961 8.76301 8.2929 8.83003 8.39041C8.89704 8.48768 9.03033 8.51237 9.12785 8.44535L10.0979 7.77714C10.1954 7.71012 10.2199 7.57681 10.1529 7.47957C10.0858 7.38206 9.95231 7.35733 9.85501 7.42463Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M4.97826 12.4473C4.1581 12.4473 3.49243 13.112 3.49243 13.9331C3.49243 14.753 4.15813 15.4177 4.97826 15.4177C5.79818 15.4177 6.46284 14.753 6.46284 13.9331C6.46284 13.1119 5.79815 12.4473 4.97826 12.4473ZM4.97826 14.4544C4.69055 14.4544 4.45567 14.2208 4.45567 13.9331C4.45567 13.6454 4.69052 13.4105 4.97826 13.4105C5.26573 13.4105 5.49957 13.6454 5.49957 13.9331C5.49957 14.2208 5.26573 14.4544 4.97826 14.4544Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.3257 5.81717C11.1156 5.08596 10.4467 4.58203 9.6857 4.58203H5.20523C4.84291 4.58203 4.5491 4.87583 4.5491 5.23816V9.41249H4.07715C3.26935 9.41249 2.6145 10.0673 2.6145 10.8751V13.4258H2.88458C3.11388 12.4815 3.96429 11.7774 4.9782 11.7774C5.99161 11.7774 6.84123 12.4815 7.07052 13.4258H8.05798C8.13812 12.1123 9.22862 11.0679 10.5618 11.0679C11.2884 11.0679 11.9421 11.3804 12.4009 11.876V11.7487V10.3279C12.4009 9.8179 12.3293 9.31021 12.1885 8.82012L11.3257 5.81717ZM10.1793 8.21563L9.49446 8.6286L10.5313 10.6025H8.67763L7.81739 9.41249H6.07579V5.66572H9.6857C9.96187 5.66572 10.208 5.85115 10.2844 6.1165L11.1471 9.11919C11.2058 9.32329 11.2487 9.53116 11.2769 9.74131L10.1793 8.21563Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M10.5616 11.7383C9.54538 11.7383 8.7207 12.5617 8.7207 13.5792C8.7207 14.5948 9.54538 15.4183 10.5616 15.4183C11.5772 15.4183 12.4007 14.5948 12.4007 13.5792C12.4007 12.5617 11.5772 11.7383 10.5616 11.7383ZM10.5616 14.225C10.2051 14.225 9.91402 13.9357 9.91402 13.5792C9.91402 13.2226 10.2051 12.9316 10.5616 12.9316C10.9176 12.9316 11.2074 13.2226 11.2074 13.5792C11.2074 13.9357 10.9176 14.225 10.5616 14.225Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M14.8484 14.1482C14.3396 14.1482 13.9269 13.7355 13.9269 13.2268V4.58203H12.7197V15.0314H18.679V14.1482H14.8484Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.85501 7.42463L8.88497 8.09259C8.78745 8.15961 8.76301 8.2929 8.83003 8.39041C8.89704 8.48768 9.03033 8.51237 9.12785 8.44535L10.0979 7.77714C10.1954 7.71012 10.2199 7.57681 10.1529 7.47957C10.0858 7.38206 9.95231 7.35733 9.85501 7.42463Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_6014_655"
|
||||
x="2.14674"
|
||||
y="4.11427"
|
||||
width="17"
|
||||
height="11.7715"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.233881"
|
||||
result="effect1_foregroundBlur_6014_655"
|
||||
/>
|
||||
</filter>
|
||||
<clipPath id="clip0_6014_655">
|
||||
<rect
|
||||
width="18.7105"
|
||||
height="18.7105"
|
||||
fill="white"
|
||||
transform="translate(0.644775 0.644531)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConveyorIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_352_182)">
|
||||
<path
|
||||
d="M8.16336 9.72707H8.82742C8.80273 9.66301 8.7893 9.59363 8.7893 9.52144V6.32707C8.7893 6.1677 8.85492 6.02238 8.95961 5.91738C9.06586 5.8127 9.21086 5.74707 9.3693 5.74707H12.8659C13.0255 5.74707 13.1705 5.81238 13.2755 5.91738C13.3805 6.02238 13.4455 6.16707 13.4455 6.32707V9.52144C13.4455 9.59363 13.4321 9.66301 13.4074 9.72707H15.918C16.4902 9.72707 17.0105 9.96113 17.3874 10.3377C17.764 10.7146 17.998 11.2349 17.998 11.8071C17.998 12.3793 17.764 12.8996 17.3871 13.2761C17.0105 13.653 16.4896 13.8874 15.918 13.8874H4.07836C3.50617 13.8874 2.98586 13.6533 2.60867 13.2761C2.23211 12.8996 1.99805 12.3793 1.99805 11.8071C1.99805 11.2361 2.23242 10.7158 2.60961 10.3383C2.8793 10.0677 3.22305 9.87082 3.60742 9.78113C3.56655 9.70067 3.54524 9.61169 3.54523 9.52144V6.32707C3.54523 6.1677 3.61086 6.02238 3.71555 5.91738C3.82148 5.8127 3.9668 5.74707 4.12492 5.74707H7.6218C7.78148 5.74707 7.92617 5.81238 8.03117 5.91738C8.13617 6.02238 8.20148 6.16707 8.20148 6.32707V9.52144C8.20148 9.59363 8.18805 9.66301 8.16336 9.72707ZM15.6268 6.7652L16.823 7.89488L15.5705 9.08207L15.183 8.67488L15.6805 8.20363L14.1824 8.20582V7.64426L15.7365 7.64207L15.2415 7.17457L15.6268 6.7652ZM5.28961 6.6077H6.46648L6.48617 8.05176L5.8543 7.66645L5.26117 8.04238L5.28961 6.6077ZM7.6218 6.2402H4.12492C4.10117 6.2402 4.0793 6.24988 4.06367 6.26551C4.04762 6.282 4.03856 6.30406 4.03836 6.32707V9.52144C4.03836 9.54551 4.04773 9.56738 4.06305 9.58269C4.07961 9.59832 4.10117 9.60801 4.12492 9.60801H7.6218C7.64492 9.60801 7.6668 9.59801 7.68273 9.58238C7.69836 9.56644 7.70836 9.54457 7.70836 9.52144V6.32707C7.70836 6.30301 7.69867 6.28145 7.68305 6.26582C7.66742 6.24988 7.64555 6.2402 7.6218 6.2402ZM10.5334 6.6077H11.7102L11.7299 8.05176L11.098 7.66645L10.5046 8.04238L10.5334 6.6077ZM12.8659 6.2402H9.3693C9.34523 6.2402 9.32336 6.24988 9.30773 6.26551C9.29169 6.282 9.28262 6.30406 9.28242 6.32707V9.52144C9.28242 9.54551 9.29211 9.56738 9.30711 9.58269C9.32367 9.59832 9.34523 9.60801 9.3693 9.60801H12.8659C12.889 9.60801 12.9109 9.59801 12.9268 9.58238C12.9424 9.56644 12.9524 9.54457 12.9524 9.52144V6.32707C12.9524 6.30301 12.9427 6.28145 12.9271 6.26582C12.9115 6.24988 12.8896 6.2402 12.8659 6.2402ZM14.7877 11.0064C15.2299 11.0064 15.5887 11.3649 15.5887 11.8071C15.5887 12.2493 15.2299 12.608 14.7877 12.608C14.3455 12.608 13.9871 12.2493 13.9871 11.8071C13.9871 11.3649 14.3455 11.0064 14.7877 11.0064ZM11.5946 11.0064C12.0368 11.0064 12.3952 11.3649 12.3952 11.8071C12.3952 12.2493 12.0368 12.608 11.5946 12.608C11.1521 12.608 10.7937 12.2493 10.7937 11.8071C10.7937 11.3649 11.1521 11.0064 11.5946 11.0064ZM8.40148 11.0064C8.84367 11.0064 9.20242 11.3649 9.20242 11.8071C9.20242 12.2493 8.84367 12.608 8.40148 12.608C7.9593 12.608 7.60086 12.2493 7.60086 11.8071C7.60086 11.3649 7.9593 11.0064 8.40148 11.0064ZM5.20836 11.0064C5.65055 11.0064 6.0093 11.3649 6.0093 11.8071C6.0093 12.2493 5.65055 12.608 5.20836 12.608C4.76617 12.608 4.40742 12.2493 4.40742 11.8071C4.40742 11.3649 4.76617 11.0064 5.20836 11.0064ZM15.918 10.3608H4.07836C3.68086 10.3608 3.3193 10.5239 3.05711 10.7861C2.7943 11.0474 2.63211 11.4089 2.63211 11.8071C2.63211 12.2043 2.79492 12.5661 3.05711 12.828C3.3193 13.0905 3.68117 13.2533 4.07836 13.2533H15.918C16.3149 13.2533 16.6768 13.0902 16.939 12.828C17.2012 12.5658 17.3643 12.2043 17.3643 11.8071C17.3643 11.4099 17.2012 11.0483 16.939 10.7861C16.6768 10.5239 16.3152 10.3608 15.918 10.3608Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.2334 9.76172L9.15527 6.13672H13.1396V9.76172H9.2334Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M3.9209 9.76172L3.84277 6.13672H7.82715V9.76172H3.9209Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.7178 6.60645H10.5303L10.499 8.05957L11.0928 7.66895L11.7334 8.05957L11.7178 6.60645Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M6.43555 6.60645H5.24805L5.2168 8.05957L5.81055 7.66895L6.45117 8.05957L6.43555 6.60645Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_352_182">
|
||||
<rect
|
||||
width="16"
|
||||
height="8.14031"
|
||||
fill="white"
|
||||
transform="translate(1.99902 5.74707)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const RoboticArmIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13.9796 9.68306L10.6387 7.13761L12.5478 5.22852L15.2523 8.25124L13.9796 9.68306Z"
|
||||
fill="white"
|
||||
/>
|
||||
<rect
|
||||
x="3.07955"
|
||||
y="15.1713"
|
||||
width="9.06818"
|
||||
height="2.06818"
|
||||
rx="0.238636"
|
||||
fill="white"
|
||||
stroke="white"
|
||||
stroke-width="0.159091"
|
||||
/>
|
||||
<rect
|
||||
x="4.59277"
|
||||
y="10.9551"
|
||||
width="2.86364"
|
||||
height="4.13636"
|
||||
fill="white"
|
||||
/>
|
||||
<rect
|
||||
x="5.22656"
|
||||
y="12.5459"
|
||||
width="0.636364"
|
||||
height="2.22727"
|
||||
rx="0.318182"
|
||||
fill="#494949"
|
||||
/>
|
||||
<rect
|
||||
x="11.2617"
|
||||
y="16.0898"
|
||||
width="0.636364"
|
||||
height="2.22727"
|
||||
rx="0.318182"
|
||||
transform="rotate(88.7682 11.2617 16.0898)"
|
||||
fill="#494949"
|
||||
/>
|
||||
<rect
|
||||
x="5.71387"
|
||||
y="8.08301"
|
||||
width="4.85107"
|
||||
height="2.86364"
|
||||
transform="rotate(-46.048 5.71387 8.08301)"
|
||||
fill="white"
|
||||
/>
|
||||
<circle
|
||||
cx="6.02326"
|
||||
cy="10.161"
|
||||
r="1.98864"
|
||||
fill="white"
|
||||
stroke="white"
|
||||
stroke-width="0.159091"
|
||||
/>
|
||||
<circle
|
||||
cx="10.4764"
|
||||
cy="5.06916"
|
||||
r="1.98864"
|
||||
fill="white"
|
||||
stroke="white"
|
||||
stroke-width="0.159091"
|
||||
/>
|
||||
<circle cx="6.02379" cy="10.1615" r="1.11364" fill="#494949" />
|
||||
<circle cx="10.4769" cy="5.06871" r="1.11364" fill="#494949" />
|
||||
<path
|
||||
d="M14.9316 8.17188C15.5026 8.17188 15.9656 8.63511 15.9658 9.20605V10.2402H13.8975V9.20605C13.8977 8.63522 14.3608 8.17207 14.9316 8.17188Z"
|
||||
fill="white"
|
||||
stroke="white"
|
||||
stroke-width="0.159091"
|
||||
/>
|
||||
<path
|
||||
d="M14.4561 10.1602H15.7295C16.3442 10.1604 16.8426 10.6587 16.8428 11.2734V13.291C16.8427 13.4108 16.7153 13.4875 16.6094 13.4316L15.834 13.0215V11.6855C15.8338 11.4222 15.6208 11.2092 15.3574 11.209H14.8799C14.6164 11.209 14.4025 11.4221 14.4023 11.6855V13.0205L13.5742 13.4424C13.4684 13.4963 13.3428 13.4186 13.3428 13.2998V11.2734C13.3429 10.6586 13.8412 10.1603 14.4561 10.1602Z"
|
||||
stroke="white"
|
||||
stroke-width="0.318182"
|
||||
/>
|
||||
<rect
|
||||
x="8.43457"
|
||||
y="6.18359"
|
||||
width="0.636364"
|
||||
height="2.22727"
|
||||
rx="0.318182"
|
||||
transform="rotate(46.5101 8.43457 6.18359)"
|
||||
fill="#494949"
|
||||
/>
|
||||
<rect
|
||||
x="14.0859"
|
||||
y="7.48438"
|
||||
width="0.636364"
|
||||
height="1.34988"
|
||||
rx="0.318182"
|
||||
transform="rotate(131.749 14.0859 7.48438)"
|
||||
fill="#494949"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MachineIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11.9369 3.38379V5.39368H10.7644V4.55635H9.5918V3.38379H11.9369Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M8.07979 12.0938H6.90723V16.2816H8.07979V12.0938Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M5.90694 12.0938H4.73438V16.2816H5.90694V12.0938Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.59346 4.55635V5.8964H8.4209V3.38379H9.59346V4.55635Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M6.40843 5.89694C6.96354 5.89694 7.41354 5.44693 7.41354 4.89183C7.41354 4.33672 6.96354 3.88672 6.40843 3.88672C5.85332 3.88672 5.40332 4.33672 5.40332 4.89183C5.40332 5.44693 5.85332 5.89694 6.40843 5.89694Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.418 5.08984V4.08984"
|
||||
stroke="#494949"
|
||||
stroke-width="0.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.7646 7.9055L10.9324 6.90039H12.2724L12.4399 7.9055H13.1097V9.91539H10.0947V7.9055H10.7646Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M14.7864 5.39258H13.7812V6.73295H14.7864V5.39258Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path d="M16.6304 16.2832H15.29V17.4558H16.6304V16.2832Z" fill="white" />
|
||||
<path
|
||||
d="M7.58266 16.2832V17.4558H4.23242V16.2832H4.73481H5.90737H7.07994H7.58266Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path d="M14.7864 13.9365H8.4209V15.1091H14.7864V13.9365Z" fill="white" />
|
||||
<path
|
||||
d="M7.08048 10.585V12.0925H5.90791H4.73535V10.585H7.08048Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M14.7862 11.2557H8.42069V13.9358V15.1083V16.2809H7.58337H7.08065V12.093V10.5855H4.73552V12.093V16.2809H4.23313H3.39551V7.23531H4.40059H8.42069V9.91537H10.096H13.1109H14.7862V6.73292V5.39258H17.1314V16.2809H16.629H15.2886H14.7862V15.1083V13.9358V11.2557Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M8.42343 5.89613V7.23615H4.40332V2.5459H8.4234V3.38355L8.42343 5.89613ZM7.41865 4.89102C7.41865 4.33596 6.96861 3.88591 6.41354 3.88591C5.85847 3.88591 5.40843 4.33596 5.40843 4.89102C5.40843 5.44609 5.85847 5.89613 6.41354 5.89613C6.96861 5.89613 7.41865 5.44609 7.41865 4.89102Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M7.41862 8.15625H4.40332V8.65963H7.41862V8.15625Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M7.41862 9.16211H4.40332V9.66549H7.41862V9.16211Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M6.41496 3.63379C5.722 3.63379 5.1582 4.19758 5.1582 4.89057C5.1582 5.58356 5.722 6.14736 6.41496 6.14736C7.10795 6.14736 7.67174 5.58356 7.67174 4.89057C7.67174 4.19758 7.10798 3.63379 6.41496 3.63379ZM6.41496 5.64401C5.99953 5.64401 5.66159 5.30603 5.66159 4.8906C5.66159 4.47518 5.99953 4.1372 6.41496 4.1372C6.83039 4.1372 7.16836 4.47518 7.16836 4.8906C7.16836 5.30603 6.83039 5.64401 6.41496 5.64401Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M6.74732 4.63965H6.07715V5.14303H6.74732V4.63965Z"
|
||||
fill="#494949"
|
||||
/>
|
||||
<path
|
||||
d="M8.91992 5.08984V4.08984"
|
||||
stroke="#494949"
|
||||
stroke-width="0.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.3857 9.08984H10.8857"
|
||||
stroke="#494949"
|
||||
stroke-width="0.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M15.9199 6.09082V12.5908"
|
||||
stroke="#494949"
|
||||
stroke-width="0.5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CraneIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M18.5 5.7502L12.875 1.3752C12.6875 1.1877 12.375 1.1877 12.125 1.3127L5.4375 5.6252H1.875C1.5 5.6252 1.25 5.8752 1.25 6.2502C1.25 6.6252 1.5 6.8752 1.875 6.8752H4.375V10.0002H1.875C1.5 10.0002 1.25 10.2502 1.25 10.6252V13.7502C1.25 14.1252 1.5 14.3752 1.875 14.3752H8.125C8.5 14.3752 8.75 14.1252 8.75 13.7502V10.6252C8.75 10.2502 8.5 10.0002 8.125 10.0002H5.625V6.8752H10.625V15.9377L8.375 17.6252C8.1875 17.8127 8.0625 18.0627 8.1875 18.3127C8.25 18.5627 8.5 18.7502 8.75 18.7502H16.25C16.5 18.7502 16.75 18.5627 16.8125 18.3127C16.875 18.0627 16.8125 17.7502 16.625 17.6252L14.375 15.9377V6.8752H18.125C18.375 6.8752 18.625 6.6877 18.6875 6.4377C18.8125 6.1877 18.75 5.9377 18.5 5.7502ZM3.6875 11.2502L2.5 12.7502V11.2502H3.6875ZM5 11.6252L6.1875 13.1252H3.8125L5 11.6252ZM7.5 12.7502L6.3125 11.2502H7.5V12.7502ZM11.875 3.0002V5.6252H11.25H7.75L11.875 3.0002ZM13.75 5.6252H13.125V3.1252L16.3125 5.6252H13.75Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
type TypeBasedAssetIconsProps = {
|
||||
assetType: string;
|
||||
};
|
||||
|
||||
export function TypeBasedAssetIcons({ assetType }: TypeBasedAssetIconsProps) {
|
||||
return (
|
||||
<div>
|
||||
{assetType === "StaticMachine" && <MachineIcon />}
|
||||
{assetType === "Vehicle" && <ForkLiftIcon />}
|
||||
{assetType === "Conveyor" && <ConveyorIcon />}
|
||||
{assetType === "Crane" && <CraneIcon />}
|
||||
{assetType === "ArmBot" && <RoboticArmIcon />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -253,3 +253,20 @@ export function LogoutIcon() {
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function WifiIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.78458 7.91952C6.35145 7.4864 5.64945 7.4864 5.21633 7.91952C4.7832 8.35265 4.7832 9.05465 5.21633 9.48777C5.64945 9.9209 6.35145 9.9209 6.78458 9.48777C7.2177 9.05465 7.2177 8.35265 6.78458 7.91952ZM9.7902 6.48215L8.67945 7.5929C7.20008 6.11352 4.8012 6.11352 3.32183 7.5929L2.21108 6.48215C4.30395 4.38927 7.69733 4.38927 9.7902 6.48215ZM10.574 5.69802C8.04795 3.17202 3.95258 3.17202 1.42658 5.69802L0.283203 4.55465C3.4407 1.39715 8.55983 1.39715 11.7173 4.55465L10.574 5.69802Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1697,93 +1697,6 @@ export const TargetIcon = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ForkLiftIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_6014_655)">
|
||||
<g filter="url(#filter0_f_6014_655)">
|
||||
<path
|
||||
d="M4.97826 12.4473C4.1581 12.4473 3.49243 13.112 3.49243 13.9331C3.49243 14.753 4.15813 15.4177 4.97826 15.4177C5.79818 15.4177 6.46284 14.753 6.46284 13.9331C6.46284 13.1119 5.79815 12.4473 4.97826 12.4473ZM4.97826 14.4544C4.69055 14.4544 4.45567 14.2208 4.45567 13.9331C4.45567 13.6454 4.69052 13.4105 4.97826 13.4105C5.26573 13.4105 5.49957 13.6454 5.49957 13.9331C5.49957 14.2208 5.26573 14.4544 4.97826 14.4544Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.3257 5.81717C11.1156 5.08596 10.4467 4.58203 9.6857 4.58203H5.20523C4.84291 4.58203 4.5491 4.87583 4.5491 5.23816V9.41249H4.07715C3.26935 9.41249 2.6145 10.0673 2.6145 10.8751V13.4258H2.88458C3.11388 12.4815 3.96429 11.7774 4.9782 11.7774C5.99161 11.7774 6.84123 12.4815 7.07052 13.4258H8.05798C8.13812 12.1123 9.22862 11.0679 10.5618 11.0679C11.2884 11.0679 11.9421 11.3804 12.4009 11.876V11.7487V10.3279C12.4009 9.8179 12.3293 9.31021 12.1885 8.82012L11.3257 5.81717ZM10.1793 8.21563L9.49446 8.6286L10.5313 10.6025H8.67763L7.81739 9.41249H6.07579V5.66572H9.6857C9.96187 5.66572 10.208 5.85115 10.2844 6.1165L11.1471 9.11919C11.2058 9.32329 11.2487 9.53116 11.2769 9.74131L10.1793 8.21563Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M10.5616 11.7383C9.54538 11.7383 8.7207 12.5617 8.7207 13.5792C8.7207 14.5948 9.54538 15.4183 10.5616 15.4183C11.5772 15.4183 12.4007 14.5948 12.4007 13.5792C12.4007 12.5617 11.5772 11.7383 10.5616 11.7383ZM10.5616 14.225C10.2051 14.225 9.91402 13.9357 9.91402 13.5792C9.91402 13.2226 10.2051 12.9316 10.5616 12.9316C10.9176 12.9316 11.2074 13.2226 11.2074 13.5792C11.2074 13.9357 10.9176 14.225 10.5616 14.225Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M14.8484 14.1482C14.3396 14.1482 13.9269 13.7355 13.9269 13.2268V4.58203H12.7197V15.0314H18.679V14.1482H14.8484Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.85501 7.42463L8.88497 8.09259C8.78745 8.15961 8.76301 8.2929 8.83003 8.39041C8.89704 8.48768 9.03033 8.51237 9.12785 8.44535L10.0979 7.77714C10.1954 7.71012 10.2199 7.57681 10.1529 7.47957C10.0858 7.38206 9.95231 7.35733 9.85501 7.42463Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
d="M4.97826 12.4473C4.1581 12.4473 3.49243 13.112 3.49243 13.9331C3.49243 14.753 4.15813 15.4177 4.97826 15.4177C5.79818 15.4177 6.46284 14.753 6.46284 13.9331C6.46284 13.1119 5.79815 12.4473 4.97826 12.4473ZM4.97826 14.4544C4.69055 14.4544 4.45567 14.2208 4.45567 13.9331C4.45567 13.6454 4.69052 13.4105 4.97826 13.4105C5.26573 13.4105 5.49957 13.6454 5.49957 13.9331C5.49957 14.2208 5.26573 14.4544 4.97826 14.4544Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M11.3257 5.81717C11.1156 5.08596 10.4467 4.58203 9.6857 4.58203H5.20523C4.84291 4.58203 4.5491 4.87583 4.5491 5.23816V9.41249H4.07715C3.26935 9.41249 2.6145 10.0673 2.6145 10.8751V13.4258H2.88458C3.11388 12.4815 3.96429 11.7774 4.9782 11.7774C5.99161 11.7774 6.84123 12.4815 7.07052 13.4258H8.05798C8.13812 12.1123 9.22862 11.0679 10.5618 11.0679C11.2884 11.0679 11.9421 11.3804 12.4009 11.876V11.7487V10.3279C12.4009 9.8179 12.3293 9.31021 12.1885 8.82012L11.3257 5.81717ZM10.1793 8.21563L9.49446 8.6286L10.5313 10.6025H8.67763L7.81739 9.41249H6.07579V5.66572H9.6857C9.96187 5.66572 10.208 5.85115 10.2844 6.1165L11.1471 9.11919C11.2058 9.32329 11.2487 9.53116 11.2769 9.74131L10.1793 8.21563Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M10.5616 11.7383C9.54538 11.7383 8.7207 12.5617 8.7207 13.5792C8.7207 14.5948 9.54538 15.4183 10.5616 15.4183C11.5772 15.4183 12.4007 14.5948 12.4007 13.5792C12.4007 12.5617 11.5772 11.7383 10.5616 11.7383ZM10.5616 14.225C10.2051 14.225 9.91402 13.9357 9.91402 13.5792C9.91402 13.2226 10.2051 12.9316 10.5616 12.9316C10.9176 12.9316 11.2074 13.2226 11.2074 13.5792C11.2074 13.9357 10.9176 14.225 10.5616 14.225Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M14.8484 14.1482C14.3396 14.1482 13.9269 13.7355 13.9269 13.2268V4.58203H12.7197V15.0314H18.679V14.1482H14.8484Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M9.85501 7.42463L8.88497 8.09259C8.78745 8.15961 8.76301 8.2929 8.83003 8.39041C8.89704 8.48768 9.03033 8.51237 9.12785 8.44535L10.0979 7.77714C10.1954 7.71012 10.2199 7.57681 10.1529 7.47957C10.0858 7.38206 9.95231 7.35733 9.85501 7.42463Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_6014_655"
|
||||
x="2.14674"
|
||||
y="4.11427"
|
||||
width="17"
|
||||
height="11.7715"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.233881"
|
||||
result="effect1_foregroundBlur_6014_655"
|
||||
/>
|
||||
</filter>
|
||||
<clipPath id="clip0_6014_655">
|
||||
<rect
|
||||
width="18.7105"
|
||||
height="18.7105"
|
||||
fill="white"
|
||||
transform="translate(0.644775 0.644531)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
export const RightHalfFillCircleIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
useLoadingProgress,
|
||||
useRenameModeStore,
|
||||
useSaveVersion,
|
||||
useSelectedAssets,
|
||||
useSelectedComment,
|
||||
useSelectedFloorItem,
|
||||
useSocketStore,
|
||||
useWidgetSubOption,
|
||||
useLoadingProgress,
|
||||
useRenameModeStore,
|
||||
useSaveVersion,
|
||||
useSelectedComment,
|
||||
useSocketStore,
|
||||
useWidgetSubOption,
|
||||
} from "../../../store/builder/store";
|
||||
import useModuleStore, { useThreeDStore } from "../../../store/useModuleStore";
|
||||
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||
@@ -27,10 +25,7 @@ import ControlsPlayer from "../controls/ControlsPlayer";
|
||||
import SelectFloorPlan from "../../temporary/SelectFloorPlan";
|
||||
import { createHandleDrop } from "../../../modules/visualization/functions/handleUiDrop";
|
||||
import Scene from "../../../modules/scene/scene";
|
||||
import {
|
||||
useComparisonProduct,
|
||||
useMainProduct,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
|
||||
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
||||
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
||||
import RenameTooltip from "../../ui/features/RenameTooltip";
|
||||
@@ -42,184 +37,172 @@ import { useVersionContext } from "../../../modules/builder/version/versionConte
|
||||
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
|
||||
import Footer from "../../footer/Footer";
|
||||
import ThreadChat from "../../ui/collaboration/ThreadChat";
|
||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||
|
||||
function MainScene() {
|
||||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedUser } = useSelectedUserStore();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
const { toggleThreeD } = useThreeDStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { widgetSubOption } = useWidgetSubOption();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { setFloatingWidget } = useFloatingWidget();
|
||||
const { clearComparisonProduct } = useComparisonProduct();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedAssets, setSelectedAssets } = useSelectedAssets();
|
||||
const { assetStore, productStore } = useSceneContext();
|
||||
const { products } = productStore();
|
||||
const { setName } = assetStore();
|
||||
const { projectId } = useParams()
|
||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||
const { versionHistory } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
const { selectedComment, commentPositionState } = useSelectedComment();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedUser } = useSelectedUserStore();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
const { toggleThreeD } = useThreeDStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { widgetSubOption } = useWidgetSubOption();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { setFloatingWidget } = useFloatingWidget();
|
||||
const { clearComparisonProduct } = useComparisonProduct();
|
||||
const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
|
||||
const { assetStore, productStore } = useSceneContext();
|
||||
const { products } = productStore();
|
||||
const { setName, selectedAssets, setSelectedAssets } = assetStore();
|
||||
const { projectId } = useParams()
|
||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||
const { versionHistory } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
const { selectedComment, commentPositionState } = useSelectedComment();
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== 'simulation') {
|
||||
clearComparisonProduct();
|
||||
setIsVersionSaved(false);
|
||||
}
|
||||
}, [activeModule, clearComparisonProduct, setIsVersionSaved])
|
||||
|
||||
useEffect(() => {
|
||||
if (versionHistory.length > 0) {
|
||||
setSelectedVersion(versionHistory[0])
|
||||
}
|
||||
}, [setSelectedVersion, versionHistory])
|
||||
|
||||
const handleSelectVersion = (option: string) => {
|
||||
const version = versionHistory.find((version) => version.versionName === option);
|
||||
if (version) {
|
||||
setSelectedVersion(version);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectProduct = (option: string) => {
|
||||
const product = products.find((product) => product.productName === option);
|
||||
if (product) {
|
||||
setMainProduct(product.productUuid, product.productName);
|
||||
}
|
||||
};
|
||||
|
||||
const handleObjectRename = async (newName: string) => {
|
||||
if (!projectId) return
|
||||
if (selectedFloorItem) {
|
||||
console.log('selectedFloorItem.userData.modelUuid: ', selectedFloorItem.userData.modelUuid);
|
||||
console.log(' newName: ', newName);
|
||||
console.log('projectId: ', projectId);
|
||||
setAssetsApi({
|
||||
modelUuid: selectedFloorItem.userData.modelUuid,
|
||||
modelName: newName,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
}).then(() => {
|
||||
selectedFloorItem.userData = {
|
||||
...selectedFloorItem.userData,
|
||||
modelName: newName
|
||||
};
|
||||
setSelectedFloorItem(selectedFloorItem);
|
||||
setIsRenameMode(false);
|
||||
setName(selectedFloorItem.userData.modelUuid, newName);
|
||||
})
|
||||
} else if (selectedAssets.length === 1) {
|
||||
setAssetsApi({
|
||||
modelUuid: selectedAssets[0].userData.modelUuid,
|
||||
modelName: newName,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
}).then(() => {
|
||||
selectedAssets[0].userData = {
|
||||
...selectedAssets[0].userData,
|
||||
modelName: newName
|
||||
};
|
||||
setSelectedAssets(selectedAssets);
|
||||
setIsRenameMode(false);
|
||||
setName(selectedAssets[0].userData.modelUuid, newName);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!selectedUser && (
|
||||
<>
|
||||
<KeyPressListener />
|
||||
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||
{!isPlaying && (
|
||||
<>
|
||||
{toggleThreeD && !isVersionSaved && <ModuleToggle />}
|
||||
<SideBarLeft />
|
||||
<SideBarRight />
|
||||
</>
|
||||
)}
|
||||
<RealTimeVisulization />
|
||||
{activeModule === "market" && <MarketPlace />}
|
||||
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||
<Tools />
|
||||
)}
|
||||
{(isPlaying) &&
|
||||
activeModule === "simulation" &&
|
||||
loadingProgress === 0 && <SimulationPlayer />}
|
||||
{(isPlaying) &&
|
||||
activeModule !== "simulation" && <ControlsPlayer />}
|
||||
|
||||
{isRenameMode && (selectedFloorItem?.userData.modelName || selectedAssets.length === 1) && <RenameTooltip name={selectedFloorItem?.userData.modelName || selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}
|
||||
{/* remove this later */}
|
||||
{activeModule === "builder" && !toggleThreeD && <SelectFloorPlan />}
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className="scene-container"
|
||||
id="work-space-three-d-canvas"
|
||||
style={{
|
||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
borderRadius:
|
||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||
}}
|
||||
role="application"
|
||||
onDrop={(event) =>
|
||||
createHandleDrop({
|
||||
widgetSubOption,
|
||||
visualizationSocket,
|
||||
selectedZone,
|
||||
setFloatingWidget,
|
||||
event,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
useEffect(() => {
|
||||
if (activeModule !== 'simulation') {
|
||||
clearComparisonProduct();
|
||||
setIsVersionSaved(false);
|
||||
}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene layout="Main Layout" />
|
||||
</div>
|
||||
}, [activeModule, clearComparisonProduct, setIsVersionSaved])
|
||||
|
||||
{selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
|
||||
<div className="selectLayout-wrapper">
|
||||
<RegularDropDown
|
||||
header={selectedVersion.versionName}
|
||||
options={versionHistory.map((v) => v.versionName)} // Pass layout names as options
|
||||
onSelect={handleSelectVersion}
|
||||
search={false}
|
||||
/>
|
||||
<br />
|
||||
<RegularDropDown
|
||||
header={selectedProduct.productName}
|
||||
options={products.map((l) => l.productName)} // Pass layout names as options
|
||||
onSelect={handleSelectProduct}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
useEffect(() => {
|
||||
if (versionHistory.length > 0) {
|
||||
setSelectedVersion(versionHistory[0])
|
||||
}
|
||||
}, [setSelectedVersion, versionHistory])
|
||||
|
||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
||||
const handleSelectVersion = (option: string) => {
|
||||
const version = versionHistory.find((version) => version.versionName === option);
|
||||
if (version) {
|
||||
setSelectedVersion(version);
|
||||
}
|
||||
};
|
||||
|
||||
<VersionSaved />
|
||||
const handleSelectProduct = (option: string) => {
|
||||
const product = products.find((product) => product.productName === option);
|
||||
if (product) {
|
||||
setMainProduct(product.productUuid, product.productName);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
(commentPositionState !== null || selectedComment !== null) &&
|
||||
<ThreadChat />
|
||||
}
|
||||
const handleObjectRename = async (newName: string) => {
|
||||
if (!projectId) return
|
||||
if (selectedFloorAsset) {
|
||||
setAssetsApi({
|
||||
modelUuid: selectedFloorAsset.userData.modelUuid,
|
||||
modelName: newName,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
}).then(() => {
|
||||
selectedFloorAsset.userData = { ...selectedFloorAsset.userData, modelName: newName };
|
||||
setSelectedFloorAsset(selectedFloorAsset);
|
||||
setIsRenameMode(false);
|
||||
setName(selectedFloorAsset.userData.modelUuid, newName);
|
||||
})
|
||||
} else if (selectedAssets.length === 1) {
|
||||
setAssetsApi({
|
||||
modelUuid: selectedAssets[0].userData.modelUuid,
|
||||
modelName: newName,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
}).then(() => {
|
||||
selectedAssets[0].userData = { ...selectedAssets[0].userData, modelName: newName };
|
||||
setSelectedAssets(selectedAssets);
|
||||
setIsRenameMode(false);
|
||||
setName(selectedAssets[0].userData.modelUuid, newName);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{!selectedUser && (
|
||||
<>
|
||||
<KeyPressListener />
|
||||
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||
{!isPlaying && (
|
||||
<>
|
||||
{toggleThreeD && !isVersionSaved && <ModuleToggle />}
|
||||
<SideBarLeft />
|
||||
<SideBarRight />
|
||||
</>
|
||||
)}
|
||||
<RealTimeVisulization />
|
||||
{activeModule === "market" && <MarketPlace />}
|
||||
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||
<Tools />
|
||||
)}
|
||||
{(isPlaying) && activeModule === "simulation" && loadingProgress === 0 && <SimulationPlayer />}
|
||||
{(isPlaying) && activeModule !== "simulation" && <ControlsPlayer />}
|
||||
|
||||
{isRenameMode && (selectedFloorAsset?.userData.modelName || selectedAssets.length === 1) && <RenameTooltip name={selectedFloorAsset?.userData.modelName || selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}
|
||||
{/* remove this later */}
|
||||
{activeModule === "builder" && !toggleThreeD && <SelectFloorPlan />}
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className="scene-container"
|
||||
id="work-space-three-d-canvas"
|
||||
style={{
|
||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||
borderRadius:
|
||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||
}}
|
||||
role="application"
|
||||
onDrop={(event) =>
|
||||
createHandleDrop({
|
||||
widgetSubOption,
|
||||
visualizationSocket,
|
||||
selectedZone,
|
||||
setFloatingWidget,
|
||||
event,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
})
|
||||
}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene layout="Main Layout" />
|
||||
</div>
|
||||
|
||||
{selectedProduct && selectedVersion && isVersionSaved && !isPlaying && activeModule === "simulation" && (
|
||||
<div className="selectLayout-wrapper">
|
||||
<RegularDropDown
|
||||
header={selectedVersion.versionName}
|
||||
options={versionHistory.map((v) => v.versionName)} // Pass layout names as options
|
||||
onSelect={handleSelectVersion}
|
||||
search={false}
|
||||
/>
|
||||
<br />
|
||||
<RegularDropDown
|
||||
header={selectedProduct.productName}
|
||||
options={products.map((l) => l.productName)} // Pass layout names as options
|
||||
onSelect={handleSelectProduct}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
||||
|
||||
<VersionSaved />
|
||||
|
||||
{
|
||||
(commentPositionState !== null || selectedComment !== null) &&
|
||||
<ThreadChat />
|
||||
}
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MainScene;
|
||||
|
||||
@@ -1,307 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Search from "../../ui/inputs/Search";
|
||||
import { getCategoryAsset } from "../../../services/factoryBuilder/asset/assets/getCategoryAsset";
|
||||
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
|
||||
import { useDecalStore, useSelectedItem } from "../../../store/builder/store";
|
||||
|
||||
// images -------------------
|
||||
import vehicle from "../../../assets/image/categories/vehicles.png";
|
||||
import workStation from "../../../assets/image/categories/workStation.png";
|
||||
import machines from "../../../assets/image/categories/machines.png";
|
||||
import worker from "../../../assets/image/categories/worker.png";
|
||||
import storage from "../../../assets/image/categories/storage.png";
|
||||
import office from "../../../assets/image/categories/office.png";
|
||||
import safety from "../../../assets/image/categories/safety.png";
|
||||
import feneration from "../../../assets/image/categories/feneration.png";
|
||||
import decal from "../../../assets/image/categories/decal.png";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
import {
|
||||
AlertIcon,
|
||||
DecalInfoIcon,
|
||||
HangTagIcon,
|
||||
NavigationIcon,
|
||||
} from "../../icons/ExportCommonIcons";
|
||||
// -------------------------------------
|
||||
|
||||
interface AssetProp {
|
||||
filename: string;
|
||||
thumbnail?: string;
|
||||
category: string;
|
||||
description?: string;
|
||||
tags: string;
|
||||
url?: string;
|
||||
uploadDate?: number;
|
||||
isArchieve?: boolean;
|
||||
animated?: boolean;
|
||||
price?: number;
|
||||
CreatedBy?: string;
|
||||
}
|
||||
interface CategoryListProp {
|
||||
assetImage?: string;
|
||||
assetName?: string;
|
||||
categoryImage: string;
|
||||
category: string;
|
||||
}
|
||||
const Assets: React.FC = () => {
|
||||
const { setSelectedItem } = useSelectedItem();
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||
const [categoryAssets, setCategoryAssets] = useState<AssetProp[]>([]);
|
||||
const [filtereredAssets, setFiltereredAssets] = useState<AssetProp[]>([]);
|
||||
const [categoryList, setCategoryList] = useState<CategoryListProp[]>([]);
|
||||
const [isLoading, setisLoading] = useState<boolean>(false); // Loading state for assets
|
||||
|
||||
const handleSearchChange = (value: string) => {
|
||||
const searchTerm = value.toLowerCase();
|
||||
setSearchValue(value);
|
||||
if (searchTerm.trim() === "" && !selectedCategory) {
|
||||
setCategoryAssets([]);
|
||||
return;
|
||||
}
|
||||
const filteredModels = filtereredAssets?.filter((model) => {
|
||||
if (!model?.tags || !model?.filename || !model?.category) return false;
|
||||
if (searchTerm.startsWith(":") && searchTerm.length > 1) {
|
||||
const tagSearchTerm = searchTerm.slice(1);
|
||||
return model.tags.toLowerCase().includes(tagSearchTerm);
|
||||
} else if (selectedCategory) {
|
||||
return (
|
||||
model.category
|
||||
.toLowerCase()
|
||||
.includes(selectedCategory.toLowerCase()) &&
|
||||
model.filename.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
} else {
|
||||
return model.filename.toLowerCase().includes(searchTerm);
|
||||
}
|
||||
});
|
||||
|
||||
setCategoryAssets(filteredModels);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const filteredAssets = async () => {
|
||||
try {
|
||||
const filt = await fetchAssets();
|
||||
setFiltereredAssets(filt);
|
||||
} catch {
|
||||
echo.error("Filter asset not found");
|
||||
}
|
||||
};
|
||||
filteredAssets();
|
||||
}, [categoryAssets]);
|
||||
|
||||
useEffect(() => {
|
||||
setCategoryList([
|
||||
{ category: "Fenestration", categoryImage: feneration },
|
||||
{ category: "Decals", categoryImage: decal },
|
||||
{ category: "Vehicles", categoryImage: vehicle },
|
||||
{ category: "Workstation", categoryImage: workStation },
|
||||
{ category: "Machines", categoryImage: machines },
|
||||
{ category: "Workers", categoryImage: worker },
|
||||
{ category: "Storage", categoryImage: storage },
|
||||
{ category: "Safety", categoryImage: safety },
|
||||
{ category: "Office", categoryImage: office },
|
||||
]);
|
||||
}, []);
|
||||
|
||||
const fetchCategoryAssets = async (asset: any) => {
|
||||
setisLoading(true);
|
||||
setSelectedCategory(asset);
|
||||
try {
|
||||
const res = await getCategoryAsset(asset);
|
||||
setCategoryAssets(res);
|
||||
setFiltereredAssets(res);
|
||||
setisLoading(false); // End loading
|
||||
// eslint-disable-next-line
|
||||
} catch (error) {
|
||||
echo.error("failed to fetch assets");
|
||||
setisLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const activeSubcategories = [
|
||||
{ name: "Safety", icon: <AlertIcon /> },
|
||||
{ name: "Navigation", icon: <NavigationIcon /> },
|
||||
{ name: "Branding", icon: <HangTagIcon /> },
|
||||
{ name: "Informational", icon: <DecalInfoIcon /> },
|
||||
];
|
||||
|
||||
const { selectedSubCategory, setSelectedSubCategory } = useDecalStore();
|
||||
return (
|
||||
<div className="assets-container-main">
|
||||
<Search onChange={handleSearchChange} />
|
||||
<div className="assets-list-section">
|
||||
<section>
|
||||
{(() => {
|
||||
if (isLoading) {
|
||||
return <SkeletonUI type="asset" />; // Show skeleton when loading
|
||||
}
|
||||
if (searchValue) {
|
||||
return (
|
||||
<div className="assets-result">
|
||||
<div className="assets-wrapper">
|
||||
<div className="searched-content">
|
||||
<p>Results for {searchValue}</p>
|
||||
</div>
|
||||
<div className="assets-container">
|
||||
{categoryAssets?.map((asset: any, index: number) => (
|
||||
<div
|
||||
key={`${index}-${asset.filename}`}
|
||||
className="assets"
|
||||
id={asset.filename}
|
||||
title={asset.filename}
|
||||
>
|
||||
<img
|
||||
src={asset?.thumbnail}
|
||||
alt={asset.filename}
|
||||
className="asset-image"
|
||||
onPointerDown={() => {
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.AssetID,
|
||||
type:
|
||||
asset.type === "undefined"
|
||||
? undefined
|
||||
: asset.type,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="asset-name">
|
||||
{asset.filename
|
||||
.split("_")
|
||||
.map(
|
||||
(word: any) =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
)
|
||||
.join(" ")}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedCategory) {
|
||||
return (
|
||||
<div className="assets-wrapper">
|
||||
<h2>
|
||||
{selectedCategory}
|
||||
<button
|
||||
className="back-button"
|
||||
id="asset-backButtom"
|
||||
onClick={() => {
|
||||
setSelectedCategory(null);
|
||||
setSelectedSubCategory(null);
|
||||
setCategoryAssets([]);
|
||||
}}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
{selectedCategory === "Decals" && (
|
||||
<>
|
||||
<div className="catogory-asset-filter">
|
||||
{activeSubcategories.map((cat, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`catogory-asset-filter-wrapper ${
|
||||
selectedSubCategory === cat.name ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedSubCategory(cat.name)}
|
||||
>
|
||||
<div className="sub-catagory">{cat.icon}</div>
|
||||
<div className="sub-catagory">{cat.name}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="assets-container">
|
||||
{categoryAssets?.map((asset: any, index: number) => (
|
||||
<div
|
||||
key={`${index}-${asset}`}
|
||||
className="assets"
|
||||
id={asset.filename}
|
||||
title={asset.filename}
|
||||
>
|
||||
<img
|
||||
src={asset?.thumbnail}
|
||||
alt={asset.filename}
|
||||
className="asset-image"
|
||||
onPointerDown={() => {
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.AssetID,
|
||||
type:
|
||||
asset.type === "undefined"
|
||||
? undefined
|
||||
: asset.type,
|
||||
category: asset.category,
|
||||
subType: asset.subType,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="asset-name">
|
||||
{asset.filename
|
||||
.split("_")
|
||||
.map(
|
||||
(word: any) =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
)
|
||||
.join(" ")}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{categoryAssets.length === 0 && (
|
||||
<div className="no-asset">
|
||||
🚧 The asset shelf is empty. We're working on filling it
|
||||
up!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="assets-wrapper">
|
||||
<h2>Categories</h2>
|
||||
<div className="categories-container">
|
||||
{Array.from(
|
||||
new Set(categoryList.map((asset) => asset.category))
|
||||
).map((category, index) => {
|
||||
const categoryInfo = categoryList.find(
|
||||
(asset) => asset.category === category
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={`${index}-${category}`}
|
||||
className="category"
|
||||
id={category}
|
||||
onClick={() => fetchCategoryAssets(category)}
|
||||
>
|
||||
<img
|
||||
src={categoryInfo?.categoryImage ?? ""}
|
||||
alt={category}
|
||||
className="category-image"
|
||||
draggable={false}
|
||||
/>
|
||||
<div className="category-name">{category}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Assets;
|
||||
@@ -3,7 +3,7 @@ import ToggleHeader from "../../ui/inputs/ToggleHeader";
|
||||
import Outline from "./Outline";
|
||||
import Header from "./Header";
|
||||
import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||
import Assets from "./Assets";
|
||||
import Assets from "./assetList/Assets";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import Widgets from "./visualization/widgets/Widgets";
|
||||
import Templates from "../../../modules/visualization/template/Templates";
|
||||
|
||||
176
app/src/components/layout/sidebarLeft/assetList/Assets.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
||||
import { getFilteredAssets } from "./assetsHelpers/filteredAssetsHelper";
|
||||
import { fetchCategoryDecals } from "./assetsHelpers/fetchDecalsHelper";
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import {
|
||||
fetchAllAssets,
|
||||
fetchCategoryAssets,
|
||||
} from "./assetsHelpers/fetchAssetsHelper";
|
||||
import Search from "../../../ui/inputs/Search";
|
||||
import SkeletonUI from "../../../templates/SkeletonUI";
|
||||
import { RenderAsset } from "./assetsHelpers/renderAssetHelper";
|
||||
import {
|
||||
ACTIVE_DECAL_SUBCATEGORIES,
|
||||
CATEGORY_LIST,
|
||||
} from "./assetsHelpers/constants";
|
||||
import { ArrowIcon } from "../../../icons/ExportCommonIcons";
|
||||
|
||||
const Assets: React.FC = () => {
|
||||
const { selectedDecalCategory, setSelectedDecalCategory } = useBuilderStore();
|
||||
const [searchValue, setSearchValue] = useState<string | null>(null);
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||
const [assets, setAssets] = useState<AssetProp[] | DecalProp[]>([]);
|
||||
const [globalResults, setGlobalResults] = useState<(AssetProp | DecalProp)[]>(
|
||||
[]
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const filteredAssets = useMemo(
|
||||
() =>
|
||||
getFilteredAssets({
|
||||
assets,
|
||||
searchValue,
|
||||
selectedCategory,
|
||||
selectedDecalCategory,
|
||||
}),
|
||||
[assets, searchValue, selectedCategory, selectedDecalCategory]
|
||||
);
|
||||
|
||||
const handleFetchCategory = useCallback(
|
||||
async (category: string) => {
|
||||
setIsLoading(true);
|
||||
setSelectedCategory(category);
|
||||
if (category === "Decals") {
|
||||
const res = await fetchCategoryDecals("Safety");
|
||||
setAssets(res);
|
||||
setSelectedDecalCategory("Safety");
|
||||
} else {
|
||||
const res = await fetchCategoryAssets(category);
|
||||
setAssets(res);
|
||||
}
|
||||
setIsLoading(false);
|
||||
},
|
||||
[setSelectedDecalCategory]
|
||||
);
|
||||
|
||||
const fetchGlobalSearch = useCallback(async (term: string) => {
|
||||
setIsLoading(true);
|
||||
const allAssets = await fetchAllAssets();
|
||||
const lowerTerm = term.toLowerCase();
|
||||
const matches = allAssets.filter(
|
||||
(a) =>
|
||||
a.filename.toLowerCase().includes(lowerTerm) ||
|
||||
a.tags?.toLowerCase().includes(lowerTerm) ||
|
||||
a.category?.toLowerCase().includes(lowerTerm)
|
||||
);
|
||||
setGlobalResults(matches);
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedCategory && searchValue?.trim())
|
||||
fetchGlobalSearch(searchValue);
|
||||
else setGlobalResults([]);
|
||||
}, [searchValue, selectedCategory, fetchGlobalSearch]);
|
||||
|
||||
return (
|
||||
<div className="assets-container-main">
|
||||
<Search debounced onChange={setSearchValue} value={searchValue} />
|
||||
<div className="assets-list-section">
|
||||
<section>
|
||||
{isLoading ? (
|
||||
<SkeletonUI type="asset" />
|
||||
) : searchValue || selectedCategory ? (
|
||||
<div className="assets-wrapper">
|
||||
{selectedCategory ? (
|
||||
<>
|
||||
<h2 className="header">
|
||||
{selectedCategory}
|
||||
<button
|
||||
className="back-button"
|
||||
onClick={() => {
|
||||
setSelectedCategory(null);
|
||||
setSelectedDecalCategory(null);
|
||||
setAssets([]);
|
||||
setSearchValue(null);
|
||||
}}
|
||||
>
|
||||
<div className="back-arrow">
|
||||
<ArrowIcon />
|
||||
</div>{" "}
|
||||
Back
|
||||
</button>
|
||||
</h2>
|
||||
{selectedCategory === "Decals" && (
|
||||
<div className="catogory-asset-filter">
|
||||
{ACTIVE_DECAL_SUBCATEGORIES.map((cat) => (
|
||||
<div
|
||||
key={cat.name}
|
||||
className={`catogory-asset-filter-wrapper ${selectedDecalCategory === cat.name ? "active" : ""
|
||||
}`}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
const res = await fetchCategoryDecals(cat.name);
|
||||
setAssets(res);
|
||||
setSelectedDecalCategory(cat.name);
|
||||
setIsLoading(false);
|
||||
}}
|
||||
>
|
||||
<div className="sub-catagory">{cat.icon}</div>
|
||||
<div className="sub-catagory">{cat.name}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="assets-container">
|
||||
{filteredAssets.map((a, i) => (
|
||||
<RenderAsset key={i} asset={a} index={i} />
|
||||
))}
|
||||
{filteredAssets.length === 0 && (
|
||||
<div className="no-asset">🚧 No assets found</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h2 className="header">Global Search Results</h2>
|
||||
<div className="assets-container">
|
||||
{globalResults.map((a, i) => (
|
||||
<RenderAsset key={i} asset={a} index={i} />
|
||||
))}
|
||||
{globalResults.length === 0 && (
|
||||
<div className="no-asset">🔎 No matches found</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="assets-wrapper">
|
||||
<h2 className="categories-header">Categories</h2>
|
||||
<div className="categories-container">
|
||||
{CATEGORY_LIST.map((cat) => (
|
||||
<div
|
||||
key={cat.category}
|
||||
className="category"
|
||||
onClick={() => handleFetchCategory(cat.category)}
|
||||
>
|
||||
<img
|
||||
src={cat.categoryImage}
|
||||
alt={cat.category}
|
||||
className="category-image"
|
||||
draggable={false}
|
||||
/>
|
||||
<div className="category-name">{cat.category}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Assets;
|
||||
@@ -0,0 +1,34 @@
|
||||
import vehicle from "../../../../../assets/image/categories/vehicles.png";
|
||||
import workStation from "../../../../../assets/image/categories/workStation.png";
|
||||
import machines from "../../../../../assets/image/categories/machines.png";
|
||||
import worker from "../../../../../assets/image/categories/worker.png";
|
||||
import storage from "../../../../../assets/image/categories/storage.png";
|
||||
import office from "../../../../../assets/image/categories/office.png";
|
||||
import safety from "../../../../../assets/image/categories/safety.png";
|
||||
import feneration from "../../../../../assets/image/categories/feneration.png";
|
||||
import decal from "../../../../../assets/image/categories/decal.png";
|
||||
import {
|
||||
AlertIcon,
|
||||
DecalInfoIcon,
|
||||
HangTagIcon,
|
||||
NavigationIcon,
|
||||
} from "../../../../icons/ExportCommonIcons";
|
||||
|
||||
export const CATEGORY_LIST: CategoryListProp[] = [
|
||||
{ category: "Fenestration", categoryImage: feneration },
|
||||
{ category: "Decals", categoryImage: decal },
|
||||
{ category: "Vehicles", categoryImage: vehicle },
|
||||
{ category: "Workstation", categoryImage: workStation },
|
||||
{ category: "Machines", categoryImage: machines },
|
||||
{ category: "Workers", categoryImage: worker },
|
||||
{ category: "Storage", categoryImage: storage },
|
||||
{ category: "Safety", categoryImage: safety },
|
||||
{ category: "Office", categoryImage: office },
|
||||
];
|
||||
|
||||
export const ACTIVE_DECAL_SUBCATEGORIES = [
|
||||
{ name: "Safety", icon: <AlertIcon /> },
|
||||
{ name: "Navigation", icon: <NavigationIcon /> },
|
||||
{ name: "Branding", icon: <HangTagIcon /> },
|
||||
{ name: "Informational", icon: <DecalInfoIcon /> },
|
||||
];
|
||||
@@ -0,0 +1,22 @@
|
||||
import { getCategoryAsset } from "../../../../../services/factoryBuilder/asset/assets/getCategoryAsset";
|
||||
import { fetchAssets } from "../../../../../services/marketplace/fetchAssets";
|
||||
|
||||
export const fetchCategoryAssets = async (category: string): Promise<AssetProp[]> => {
|
||||
if (category === "Decals") return []; // handled separately
|
||||
try {
|
||||
const res = await getCategoryAsset(category);
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch category assets", err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchAllAssets = async (): Promise<AssetProp[]> => {
|
||||
try {
|
||||
return await fetchAssets();
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch all assets", err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getCategoryDecals } from "../../../../../services/factoryBuilder/asset/decals/getCategoryDecals";
|
||||
|
||||
export const fetchCategoryDecals = async (subcategory: string): Promise<DecalProp[]> => {
|
||||
try {
|
||||
const res = await getCategoryDecals(subcategory);
|
||||
return res;
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch decals", err);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
interface FilterProps {
|
||||
assets: AssetProp[] | DecalProp[];
|
||||
searchValue: string | null;
|
||||
selectedCategory: string | null;
|
||||
selectedDecalCategory: string | null;
|
||||
}
|
||||
|
||||
export const getFilteredAssets = ({
|
||||
assets,
|
||||
searchValue,
|
||||
selectedCategory,
|
||||
selectedDecalCategory,
|
||||
}: FilterProps) => {
|
||||
const term = searchValue?.trim().toLowerCase();
|
||||
if (!term) return assets;
|
||||
|
||||
if (selectedCategory === "Decals" || selectedDecalCategory) {
|
||||
return (assets as DecalProp[]).filter((a) =>
|
||||
a.decalName?.toLowerCase().includes(term)
|
||||
);
|
||||
}
|
||||
|
||||
return (assets as AssetProp[]).filter((a) => {
|
||||
const tags = a.tags?.toLowerCase() ?? "";
|
||||
const filename = a.filename?.toLowerCase() ?? "";
|
||||
const category = a.category?.toLowerCase() ?? "";
|
||||
|
||||
if (term.startsWith(":")) return tags.includes(term.slice(1));
|
||||
if (selectedCategory)
|
||||
return category.includes(selectedCategory.toLowerCase()) && filename.includes(term);
|
||||
|
||||
return filename.includes(term);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import { useSelectedItem } from "../../../../../store/builder/store";
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
|
||||
export const RenderAsset: React.FC<{ asset: AssetProp | DecalProp; index: number }> = ({ asset, index }) => {
|
||||
const { setSelectedItem } = useSelectedItem();
|
||||
const { setDroppedDecal } = useBuilderStore();
|
||||
|
||||
if ("decalName" in asset) {
|
||||
return (
|
||||
<div key={`${index}-${asset.decalName}`} className="assets" id={asset.decalName} title={asset.decalName}>
|
||||
<img
|
||||
src={asset.decalImage}
|
||||
alt={asset.decalName}
|
||||
className="asset-image"
|
||||
onPointerDown={() => {
|
||||
setDroppedDecal({
|
||||
category: asset.category,
|
||||
decalName: asset.decalName,
|
||||
decalImage: asset.decalImage,
|
||||
decalId: asset.id,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<div className="asset-name">
|
||||
{asset.decalName
|
||||
.split("_")
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||
.join(" ")}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={`${index}-${asset.filename}`} className="assets" id={asset.filename} title={asset.filename}>
|
||||
<img
|
||||
src={asset.thumbnail}
|
||||
alt={asset.filename}
|
||||
className="asset-image"
|
||||
onPointerDown={() =>
|
||||
setSelectedItem({
|
||||
name: asset.filename,
|
||||
id: asset.AssetID,
|
||||
type: asset.type === "undefined" ? undefined : asset.type,
|
||||
category: asset.category,
|
||||
subType: asset.subType,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="asset-name">
|
||||
{asset.filename
|
||||
.split("_")
|
||||
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||
.join(" ")}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,29 +1,13 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Header from "./Header";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
} from "../../../store/useModuleStore";
|
||||
import {
|
||||
AnalysisIcon,
|
||||
FilePackageIcon,
|
||||
MechanicsIcon,
|
||||
PropertiesIcon,
|
||||
SimulationIcon,
|
||||
} from "../../icons/SimulationIcons";
|
||||
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import { AnalysisIcon, FilePackageIcon, MechanicsIcon, PropertiesIcon, SimulationIcon, } from "../../icons/SimulationIcons";
|
||||
import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||
import Visualization from "./visualization/Visualization";
|
||||
import Analysis from "./analysis/Analysis";
|
||||
import Simulations from "./simulation/Simulations";
|
||||
import useVersionHistoryVisibleStore, {
|
||||
useDecalStore,
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
useToolMode,
|
||||
} from "../../../store/builder/store";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import useVersionHistoryVisibleStore, { useSaveVersion, useToolMode } from "../../../store/builder/store";
|
||||
import { useSelectedEventData, useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore";
|
||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||
import GlobalProperties from "./properties/GlobalProperties";
|
||||
import AssetProperties from "./properties/AssetProperties";
|
||||
@@ -35,319 +19,280 @@ import WallProperties from "./properties/WallProperties";
|
||||
import FloorProperties from "./properties/FloorProperties";
|
||||
import SelectedWallProperties from "./properties/SelectedWallProperties";
|
||||
import SelectedFloorProperties from "./properties/SelectedFloorProperties";
|
||||
import SelectedDecalProperties from "./properties/SelectedDecalProperties";
|
||||
import SelectedAisleProperties from "./properties/SelectedAisleProperties";
|
||||
import ResourceManagement from "./resourceManagement/ResourceManagement";
|
||||
import DecalProperties from "./properties/DecalProperties";
|
||||
|
||||
type DisplayComponent =
|
||||
| "versionHistory"
|
||||
| "globalProperties"
|
||||
| "aisleProperties"
|
||||
| "wallProperties"
|
||||
| "floorProperties"
|
||||
| "assetProperties"
|
||||
| "selectedWallProperties"
|
||||
| "selectedFloorProperties"
|
||||
| "zoneProperties"
|
||||
| "simulations"
|
||||
| "mechanics"
|
||||
| "analysis"
|
||||
| "visualization"
|
||||
| "selectedDecalProperties"
|
||||
| "resourceManagement"
|
||||
| "none";
|
||||
| "versionHistory"
|
||||
| "globalProperties"
|
||||
| "aisleProperties"
|
||||
| "wallProperties"
|
||||
| "floorProperties"
|
||||
| "assetProperties"
|
||||
| "selectedWallProperties"
|
||||
| "selectedFloorProperties"
|
||||
| "selectedDecalProperties"
|
||||
| "selectedAisleProperties"
|
||||
| "zoneProperties"
|
||||
| "simulations"
|
||||
| "mechanics"
|
||||
| "analysis"
|
||||
| "visualization"
|
||||
| "resourceManagement"
|
||||
| "none";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleUIRight } = useToggleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedWall, selectedFloor, selectedAisle } = useBuilderStore();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistoryVisible } =
|
||||
useVersionHistoryVisibleStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
const { selectedSubCategory } = useDecalStore();
|
||||
const { selectedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleUIRight } = useToggleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedWall, selectedFloor, selectedAisle, selectedFloorAsset } = useBuilderStore();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
|
||||
const [displayComponent, setDisplayComponent] =
|
||||
useState<DisplayComponent>("none");
|
||||
const [displayComponent, setDisplayComponent] = useState<DisplayComponent>("none");
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== "simulation") setSubModule("properties");
|
||||
if (activeModule === "simulation") setSubModule("simulations");
|
||||
}, [activeModule, setSubModule]);
|
||||
useEffect(() => {
|
||||
if (activeModule !== "simulation") setSubModule("properties");
|
||||
if (activeModule === "simulation") setSubModule("simulations");
|
||||
}, [activeModule, setSubModule]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
activeModule !== "mechanics" &&
|
||||
selectedEventData &&
|
||||
selectedEventSphere
|
||||
) {
|
||||
setSubModule("mechanics");
|
||||
} else if (!selectedEventData && !selectedEventSphere) {
|
||||
if (activeModule === "simulation") {
|
||||
setSubModule("simulations");
|
||||
}
|
||||
}
|
||||
if (activeModule !== "simulation") {
|
||||
setSubModule("properties");
|
||||
}
|
||||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule === "visualization") {
|
||||
setDisplayComponent("visualization");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isVersionSaved && activeModule === "simulation") {
|
||||
if (subModule === "simulations") {
|
||||
setDisplayComponent("simulations");
|
||||
return;
|
||||
}
|
||||
if (subModule === "mechanics") {
|
||||
setDisplayComponent("mechanics");
|
||||
return;
|
||||
}
|
||||
if (subModule === "analysis") {
|
||||
setDisplayComponent("analysis");
|
||||
return;
|
||||
}
|
||||
if (subModule === "resourceManagement") {
|
||||
setDisplayComponent("resourceManagement");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeModule === "simulation" || activeModule === "builder") {
|
||||
if (subModule === "resourceManagement") {
|
||||
setDisplayComponent("resourceManagement");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (subModule === "properties" && activeModule !== "visualization") {
|
||||
if (selectedFloorItem) {
|
||||
setDisplayComponent("assetProperties");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!selectedFloorItem &&
|
||||
!selectedFloor &&
|
||||
!selectedAisle &&
|
||||
selectedWall
|
||||
) {
|
||||
setDisplayComponent("selectedWallProperties");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!selectedFloorItem &&
|
||||
!selectedWall &&
|
||||
!selectedAisle &&
|
||||
selectedFloor
|
||||
) {
|
||||
setDisplayComponent("selectedFloorProperties");
|
||||
return;
|
||||
}
|
||||
if (viewVersionHistory) {
|
||||
setDisplayComponent("versionHistory");
|
||||
return;
|
||||
}
|
||||
if (selectedSubCategory) {
|
||||
setDisplayComponent("selectedDecalProperties");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!selectedFloorItem &&
|
||||
!selectedFloor &&
|
||||
!selectedWall &&
|
||||
!selectedSubCategory
|
||||
) {
|
||||
if (toolMode === "Aisle") {
|
||||
setDisplayComponent("aisleProperties");
|
||||
return;
|
||||
useEffect(() => {
|
||||
if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) {
|
||||
setSubModule("mechanics");
|
||||
} else if (!selectedEventData && !selectedEventSphere) {
|
||||
if (activeModule === "simulation") {
|
||||
setSubModule("simulations");
|
||||
}
|
||||
}
|
||||
if (toolMode === "Wall") {
|
||||
setDisplayComponent("wallProperties");
|
||||
return;
|
||||
if (activeModule !== "simulation") {
|
||||
setSubModule("properties");
|
||||
}
|
||||
if (toolMode === "Floor") {
|
||||
setDisplayComponent("floorProperties");
|
||||
return;
|
||||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule === "visualization") {
|
||||
setDisplayComponent("visualization");
|
||||
return;
|
||||
}
|
||||
setDisplayComponent("globalProperties");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
subModule === "zoneProperties" &&
|
||||
(activeModule === "builder" || activeModule === "simulation")
|
||||
) {
|
||||
setDisplayComponent("zoneProperties");
|
||||
return;
|
||||
}
|
||||
if (!isVersionSaved && activeModule === "simulation") {
|
||||
if (subModule === "simulations") {
|
||||
setDisplayComponent("simulations");
|
||||
return;
|
||||
}
|
||||
if (subModule === "mechanics") {
|
||||
setDisplayComponent("mechanics");
|
||||
return;
|
||||
}
|
||||
if (subModule === "analysis") {
|
||||
setDisplayComponent("analysis");
|
||||
return;
|
||||
}
|
||||
if (subModule === "resourceManagement") {
|
||||
setDisplayComponent("resourceManagement");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setDisplayComponent("none");
|
||||
}, [
|
||||
viewVersionHistory,
|
||||
activeModule,
|
||||
subModule,
|
||||
isVersionSaved,
|
||||
selectedFloorItem,
|
||||
selectedWall,
|
||||
selectedFloor,
|
||||
selectedAisle,
|
||||
toolMode,
|
||||
selectedSubCategory,
|
||||
]);
|
||||
if (activeModule === "simulation" || activeModule === "builder") {
|
||||
if (subModule === "resourceManagement") {
|
||||
setDisplayComponent("resourceManagement");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const renderComponent = () => {
|
||||
switch (displayComponent) {
|
||||
case "versionHistory":
|
||||
return <VersionHistory />;
|
||||
case "globalProperties":
|
||||
return <GlobalProperties />;
|
||||
case "aisleProperties":
|
||||
return <AisleProperties />;
|
||||
case "wallProperties":
|
||||
return <WallProperties />;
|
||||
case "floorProperties":
|
||||
return <FloorProperties />;
|
||||
case "assetProperties":
|
||||
return <AssetProperties />;
|
||||
case "selectedWallProperties":
|
||||
return <SelectedWallProperties />;
|
||||
case "selectedFloorProperties":
|
||||
return <SelectedFloorProperties />;
|
||||
case "zoneProperties":
|
||||
return <ZoneProperties />;
|
||||
case "simulations":
|
||||
return <Simulations />;
|
||||
case "mechanics":
|
||||
return <EventProperties />;
|
||||
case "analysis":
|
||||
return <Analysis />;
|
||||
case "visualization":
|
||||
return <Visualization />;
|
||||
case "selectedDecalProperties":
|
||||
return <DecalProperties />;
|
||||
case "resourceManagement":
|
||||
return <ResourceManagement />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (subModule === "properties" && activeModule !== "visualization") {
|
||||
if (selectedFloorAsset) {
|
||||
setDisplayComponent("assetProperties");
|
||||
return;
|
||||
}
|
||||
if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedDecal && selectedWall) {
|
||||
setDisplayComponent("selectedWallProperties");
|
||||
return;
|
||||
}
|
||||
if (!selectedFloorAsset && !selectedWall && !selectedAisle && !selectedDecal && selectedFloor) {
|
||||
setDisplayComponent("selectedFloorProperties");
|
||||
return;
|
||||
}
|
||||
if (viewVersionHistory && !selectedFloorAsset && !selectedWall && !selectedAisle && !selectedFloor && !selectedDecal) {
|
||||
setDisplayComponent("versionHistory");
|
||||
return;
|
||||
}
|
||||
if (!selectedFloorAsset && !selectedFloor && !selectedAisle && !selectedWall && selectedDecal) {
|
||||
setDisplayComponent("selectedDecalProperties");
|
||||
return;
|
||||
}
|
||||
if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && selectedAisle) {
|
||||
setDisplayComponent("selectedAisleProperties");
|
||||
return;
|
||||
}
|
||||
if (!selectedFloorAsset && !selectedFloor && !selectedWall && !selectedDecal && !selectedAisle) {
|
||||
if (toolMode === "Aisle") {
|
||||
setDisplayComponent("aisleProperties");
|
||||
return;
|
||||
}
|
||||
if (toolMode === "Wall") {
|
||||
setDisplayComponent("wallProperties");
|
||||
return;
|
||||
}
|
||||
if (toolMode === "Floor") {
|
||||
setDisplayComponent("floorProperties");
|
||||
return;
|
||||
}
|
||||
setDisplayComponent("globalProperties");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`sidebar-right-wrapper ${
|
||||
toggleUIRight && (!isVersionSaved || activeModule !== "simulation")
|
||||
? "open"
|
||||
: "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
<>
|
||||
{(!isVersionSaved || activeModule !== "simulation") && (
|
||||
<div className="sidebar-actions-container">
|
||||
{activeModule !== "simulation" && (
|
||||
if (subModule === "zoneProperties" && (activeModule === "builder" || activeModule === "simulation")) {
|
||||
setDisplayComponent("zoneProperties");
|
||||
return;
|
||||
}
|
||||
|
||||
setDisplayComponent("none");
|
||||
}, [viewVersionHistory, activeModule, subModule, isVersionSaved, selectedFloorAsset, selectedWall, selectedFloor, selectedAisle, toolMode, selectedDecal]);
|
||||
|
||||
const renderComponent = () => {
|
||||
switch (displayComponent) {
|
||||
case "versionHistory":
|
||||
return <VersionHistory />;
|
||||
case "globalProperties":
|
||||
return <GlobalProperties />;
|
||||
case "aisleProperties":
|
||||
return <AisleProperties />;
|
||||
case "wallProperties":
|
||||
return <WallProperties />;
|
||||
case "floorProperties":
|
||||
return <FloorProperties />;
|
||||
case "assetProperties":
|
||||
return <AssetProperties />;
|
||||
case "zoneProperties":
|
||||
return <ZoneProperties />;
|
||||
case "selectedWallProperties":
|
||||
return <SelectedWallProperties />;
|
||||
case "selectedFloorProperties":
|
||||
return <SelectedFloorProperties />;
|
||||
case "selectedDecalProperties":
|
||||
return <SelectedDecalProperties />;
|
||||
case "selectedAisleProperties":
|
||||
return <SelectedAisleProperties />;
|
||||
case "simulations":
|
||||
return <Simulations />;
|
||||
case "mechanics":
|
||||
return <EventProperties />;
|
||||
case "analysis":
|
||||
return <Analysis />;
|
||||
case "visualization":
|
||||
return <Visualization />;
|
||||
case "resourceManagement":
|
||||
return <ResourceManagement />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"}`} onPointerDown={(e) => e.stopPropagation()}>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
<>
|
||||
<button
|
||||
id="sidebar-action-list-properties"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("properties");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">properties</div>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</button>
|
||||
{(!isVersionSaved || activeModule !== "simulation") && (
|
||||
<div className="sidebar-actions-container">
|
||||
{activeModule !== "simulation" && (
|
||||
<>
|
||||
<button
|
||||
id="sidebar-action-list-properties"
|
||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("properties");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">properties</div>
|
||||
<PropertiesIcon isActive={subModule === "properties"} />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<button
|
||||
id="sidebar-action-list-simulation"
|
||||
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("simulations");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">simulations</div>
|
||||
<SimulationIcon isActive={subModule === "simulations"} />
|
||||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-mechanics"
|
||||
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("mechanics");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">mechanics</div>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-analysis"
|
||||
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("analysis");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">analysis</div>
|
||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{(activeModule === "builder" ||
|
||||
activeModule === "simulation") && (
|
||||
<button
|
||||
id="sidebar-action-list-properties"
|
||||
className={`sidebar-action-list ${subModule === "resourceManagement" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("resourceManagement");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">Resource Management</div>
|
||||
<FilePackageIcon
|
||||
isActive={subModule === "resourceManagement"}
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displayComponent !== "none" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{renderComponent()}
|
||||
{/* <ResourceManagement /> */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<button
|
||||
id="sidebar-action-list-simulation"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "simulations" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("simulations");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">simulations</div>
|
||||
<SimulationIcon isActive={subModule === "simulations"} />
|
||||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-mechanics"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "mechanics" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("mechanics");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">mechanics</div>
|
||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||
</button>
|
||||
<button
|
||||
id="sidebar-action-list-analysis"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "analysis" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("analysis");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">analysis</div>
|
||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{(activeModule === "builder" ||
|
||||
activeModule === "simulation") && (
|
||||
<button
|
||||
id="sidebar-action-list-properties"
|
||||
className={`sidebar-action-list ${
|
||||
subModule === "resourceManagement" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setSubModule("resourceManagement");
|
||||
setVersionHistoryVisible(false);
|
||||
}}
|
||||
>
|
||||
<div className="tooltip">Resource Management</div>
|
||||
<FilePackageIcon
|
||||
isActive={subModule === "resourceManagement"}
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displayComponent !== "none" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{renderComponent()}
|
||||
{/* <ResourceManagement /> */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideBarRight;
|
||||
|
||||
@@ -1,30 +1,46 @@
|
||||
import React from "react";
|
||||
|
||||
interface RotationInputProps {
|
||||
onChange: (value: string) => void; // Callback for value change
|
||||
placeholder?: string; // Optional placeholder
|
||||
type?: string; // Input type (e.g., text, number, email)
|
||||
heading?: string;
|
||||
label?: string;
|
||||
onChange: (value: string) => void;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
value?: number;
|
||||
disabled?: boolean;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
}
|
||||
|
||||
const RotationInput: React.FC<RotationInputProps> = ({
|
||||
label = "Rotate :",
|
||||
heading = "Rotation",
|
||||
onChange,
|
||||
placeholder = "Enter value", // Default placeholder
|
||||
type = "number", // Default type
|
||||
value = "number",
|
||||
placeholder = "Enter value",
|
||||
type = "number",
|
||||
value,
|
||||
disabled = false,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
}) => {
|
||||
return (
|
||||
<div className="custom-input-container">
|
||||
<div className="header">Rotation</div>
|
||||
<div className="header">{heading}</div>
|
||||
<div className="inputs-container" style={{ display: "block" }}>
|
||||
<div className="input-container">
|
||||
<div className="custom-input-label">Rotate : </div>
|
||||
<div className="custom-input-label">{label}</div>
|
||||
<input
|
||||
className="custom-input-field"
|
||||
type={type}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,24 +21,25 @@ interface TextureItem {
|
||||
texture: string;
|
||||
}
|
||||
|
||||
export const aisleTextureList: TextureItem[] = [
|
||||
{ color: "yellow", id: "#FBE50E", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "gray", id: "#6F6F7A", brief: "basic", texture: "" },
|
||||
{ color: "green", id: "#43C06D", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "orange", id: "#FF711B", brief: "material flow", texture: "" },
|
||||
{ color: "blue", id: "#488EF6", brief: "vehicle paths", texture: "" },
|
||||
{ color: "purple", id: "#AF52DE", brief: "material flow", texture: "" },
|
||||
{ color: "red", id: "#FF3B30", brief: "safety zone", texture: "" },
|
||||
{ color: "bright green", id: "#66FF00", brief: "safety zone", texture: "" },
|
||||
{ color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" },
|
||||
{ color: "white-black", id: "white-black", brief: "utility aisles", texture: "" },
|
||||
];
|
||||
|
||||
const AisleProperties: React.FC = () => {
|
||||
const [collapsePresets, setCollapsePresets] = useState(false);
|
||||
const [collapseTexture, setCollapseTexture] = useState(true);
|
||||
|
||||
const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength, setIsFlipped } = useBuilderStore();
|
||||
|
||||
const aisleTextureList: TextureItem[] = [
|
||||
{ color: "yellow", id: "yellow", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "gray", id: "gray", brief: "basic", texture: "" },
|
||||
{ color: "green", id: "green", brief: "pedestrian walkways", texture: "" },
|
||||
{ color: "orange", id: "orange", brief: "material flow", texture: "" },
|
||||
{ color: "blue", id: "blue", brief: "vehicle paths", texture: "" },
|
||||
{ color: "purple", id: "purple", brief: "material flow", texture: "" },
|
||||
{ color: "red", id: "red", brief: "safety zone", texture: "" },
|
||||
{ color: "bright green", id: "#66FF00", brief: "safety zone", texture: "" },
|
||||
{ color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" },
|
||||
{ color: "white-black", id: "white-black", brief: "utility aisles", texture: "" },
|
||||
];
|
||||
|
||||
const aisleTypes: {
|
||||
name: string;
|
||||
@@ -97,27 +98,27 @@ const AisleProperties: React.FC = () => {
|
||||
|
||||
const dashLengthValue = useMemo(() => {
|
||||
return dashLength.toString();
|
||||
}, [aisleType, dashLength]);
|
||||
}, [dashLength]);
|
||||
|
||||
const dotRadiusValue = useMemo(() => {
|
||||
return dotRadius.toString();
|
||||
}, [aisleType, dotRadius]);
|
||||
}, [dotRadius]);
|
||||
|
||||
const gapLengthValue = useMemo(() => {
|
||||
return gapLength.toString();
|
||||
}, [aisleType, gapLength]);
|
||||
}, [gapLength]);
|
||||
|
||||
const aisleWidthValue = useMemo(() => {
|
||||
return aisleWidth.toString();
|
||||
}, [aisleType, aisleWidth]);
|
||||
}, [aisleWidth]);
|
||||
|
||||
const aisleLengthValue = useMemo(() => {
|
||||
return aisleLength.toString();
|
||||
}, [aisleType, aisleLength]);
|
||||
}, [aisleLength]);
|
||||
|
||||
const aisleIsFlipped = useMemo(() => {
|
||||
return isFlipped;
|
||||
}, [aisleType, isFlipped]);
|
||||
}, [isFlipped]);
|
||||
|
||||
const renderAdvancedProperties = () => {
|
||||
switch (aisleType) {
|
||||
@@ -281,11 +282,16 @@ const AisleProperties: React.FC = () => {
|
||||
<button
|
||||
key={val.id}
|
||||
title={val.brief || val.id}
|
||||
className={`aisle-list ${aisleColor === val.color ? "selected" : ""}`}
|
||||
className={`aisle-list ${aisleColor === val.id ? "selected" : ""}`}
|
||||
onClick={() => setAisleColor(val.id)}
|
||||
aria-pressed={aisleColor === val.id}
|
||||
>
|
||||
<div className="texture-display">{val.texture}</div>
|
||||
<div
|
||||
className={`texture-display ${val.id}`}
|
||||
style={{ background: val.id }}
|
||||
>
|
||||
{val.texture}
|
||||
</div>
|
||||
<div className="aisle-color">{val.color}</div>
|
||||
<div className="aisle-brief">{`( ${val.brief} )`}</div>
|
||||
</button>
|
||||
|
||||
@@ -4,134 +4,138 @@ import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import { RemoveIcon } from "../../../icons/ExportCommonIcons";
|
||||
import PositionInput from "../customInput/PositionInputs";
|
||||
import RotationInput from "../customInput/RotationInput";
|
||||
import {
|
||||
useSelectedFloorItem,
|
||||
useObjectPosition,
|
||||
useObjectRotation,
|
||||
} from "../../../../store/builder/store";
|
||||
import { useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
interface UserData {
|
||||
id: number;
|
||||
label: string;
|
||||
value: string;
|
||||
id: number;
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const AssetProperties: React.FC = () => {
|
||||
const [userData, setUserData] = useState<UserData[]>([]);
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { objectPosition } = useObjectPosition();
|
||||
const { objectRotation } = useObjectRotation();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets, setCurrentAnimation } = assetStore();
|
||||
const { loopAnimation } = useBuilderStore();
|
||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||
const [userData, setUserData] = useState<UserData[]>([]);
|
||||
const { objectPosition } = useObjectPosition();
|
||||
const { objectRotation } = useObjectRotation();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets, setCurrentAnimation } = assetStore();
|
||||
const { loopAnimation, selectedFloorAsset } = useBuilderStore();
|
||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||
|
||||
const handleAddUserData = () => {
|
||||
setUserData([]);
|
||||
};
|
||||
const handleAddUserData = () => {
|
||||
setUserData([]);
|
||||
};
|
||||
|
||||
const handleUserDataChange = (id: number, newValue: string) => {};
|
||||
const handleUserDataChange = (id: number, newValue: string) => { };
|
||||
|
||||
const handleRemoveUserData = (id: number) => {};
|
||||
const handleRemoveUserData = (id: number) => { };
|
||||
|
||||
const handleAnimationClick = (animation: string) => {
|
||||
if (selectedFloorItem) {
|
||||
setCurrentAnimation(
|
||||
selectedFloorItem.uuid,
|
||||
animation,
|
||||
true,
|
||||
loopAnimation,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
const handleAnimationClick = (animation: string) => {
|
||||
if (selectedFloorAsset) {
|
||||
setCurrentAnimation(
|
||||
selectedFloorAsset.uuid,
|
||||
animation,
|
||||
true,
|
||||
loopAnimation,
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (!selectedFloorItem) return null;
|
||||
if (!selectedFloorAsset) return null;
|
||||
|
||||
return (
|
||||
<div className="asset-properties-container">
|
||||
{/* Name */}
|
||||
<div className="header">{selectedFloorItem.userData.modelName}</div>
|
||||
<section>
|
||||
{objectPosition && (
|
||||
<PositionInput
|
||||
onChange={() => {}}
|
||||
value1={parseFloat(objectPosition.x.toFixed(5))}
|
||||
value2={parseFloat(objectPosition.z.toFixed(5))}
|
||||
/>
|
||||
)}
|
||||
{objectRotation && (
|
||||
<RotationInput
|
||||
onChange={() => {}}
|
||||
value={parseFloat(objectRotation.y.toFixed(5))}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
return (
|
||||
<div className="asset-properties-container">
|
||||
{/* Name */}
|
||||
<div className="header">{selectedFloorAsset.userData.modelName}</div>
|
||||
<section>
|
||||
{objectPosition && (
|
||||
<PositionInput
|
||||
disabled={true}
|
||||
onChange={() => { }}
|
||||
value1={parseFloat(objectPosition.x.toFixed(5))}
|
||||
value2={parseFloat(objectPosition.z.toFixed(5))}
|
||||
/>
|
||||
)}
|
||||
{objectRotation && (
|
||||
<RotationInput
|
||||
disabled={true}
|
||||
onChange={() => { }}
|
||||
value={parseFloat(objectRotation.y.toFixed(5))}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<div className="header">Render settings</div>
|
||||
<section>
|
||||
<InputToggle inputKey="visible" label="Visible" />
|
||||
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
||||
</section>
|
||||
<div className="header">Render settings</div>
|
||||
<section>
|
||||
<InputToggle inputKey="visible" label="Visible" />
|
||||
<InputToggle inputKey="frustumCull" label="Frustum cull" />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="header">User Data</div>
|
||||
{userData.map((data) => (
|
||||
<div className="input-container">
|
||||
<InputWithDropDown
|
||||
key={data.id}
|
||||
label={data.label}
|
||||
value={data.value}
|
||||
editableLabel
|
||||
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
|
||||
/>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveUserData(data.id)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<section>
|
||||
<div className="header">User Data</div>
|
||||
{userData.map((data, i) => (
|
||||
<div className="input-container" key={i}>
|
||||
<InputWithDropDown
|
||||
key={data.id}
|
||||
label={data.label}
|
||||
value={data.value}
|
||||
editableLabel
|
||||
onChange={(newValue) => handleUserDataChange(data.id, newValue)}
|
||||
/>
|
||||
<div
|
||||
className="remove-button"
|
||||
onClick={() => handleRemoveUserData(data.id)}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Add new user data */}
|
||||
<div className="optimize-button" onClick={handleAddUserData}>
|
||||
+ Add
|
||||
{/* Add new user data */}
|
||||
<div className="optimize-button" onClick={handleAddUserData}>
|
||||
+ Add
|
||||
</div>
|
||||
</section>
|
||||
<div className="header">Animations</div>
|
||||
<section className="animations-lists">
|
||||
{assets.map((asset, i) => {
|
||||
if (asset.modelUuid !== selectedFloorAsset.uuid || !asset.animations)
|
||||
return (
|
||||
i === 0 && (
|
||||
<div className="no-animation" key={i}>
|
||||
Looks like there are no preset animations yet. Stay tuned for
|
||||
future additions!
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
return asset.animations.map((animation, index) => (
|
||||
<div key={index} className="animations-list-wrapper">
|
||||
<div
|
||||
onClick={() => handleAnimationClick(animation)}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
className="animations-list"
|
||||
style={{
|
||||
background:
|
||||
hoveredIndex === index
|
||||
? "var(--background-color-button)"
|
||||
: "var(--background-color)",
|
||||
color:
|
||||
hoveredIndex === index ? "var(--text-button-color)" : "",
|
||||
}}
|
||||
>
|
||||
{animation.charAt(0).toUpperCase() +
|
||||
animation.slice(1).toLowerCase()}
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
})}
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<div className="header">Animations</div>
|
||||
<section className="animations-lists">
|
||||
{assets.map((asset) => {
|
||||
if (asset.modelUuid !== selectedFloorItem.uuid || !asset.animations)
|
||||
return null;
|
||||
|
||||
return asset.animations.map((animation, index) => (
|
||||
<div key={index} className="animations-list-wrapper">
|
||||
<div
|
||||
onClick={() => handleAnimationClick(animation)}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
className="animations-list"
|
||||
style={{
|
||||
background:
|
||||
hoveredIndex === index
|
||||
? "var(--background-color-button)"
|
||||
: "var(--background-color)",
|
||||
color:
|
||||
hoveredIndex === index ? "var(--text-button-color)" : "",
|
||||
}}
|
||||
>
|
||||
{animation.charAt(0).toUpperCase() +
|
||||
animation.slice(1).toLowerCase()}
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
})}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default AssetProperties;
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import {
|
||||
LayeringBottomIcon,
|
||||
LayeringTopIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
import InputRange from "../../../ui/inputs/InputRange";
|
||||
import RotationInput from "../customInput/RotationInput";
|
||||
import Vector3Input from "../customInput/Vector3Input";
|
||||
|
||||
const DecalProperties = () => {
|
||||
return (
|
||||
<div className="decal-transformation-container">
|
||||
<div className="header">Decal Propertis</div>
|
||||
<section>
|
||||
<RotationInput
|
||||
onChange={() => {}}
|
||||
value={10}
|
||||
/>
|
||||
<Vector3Input
|
||||
onChange={(value) => console.log(value)}
|
||||
header="Scale"
|
||||
value={[0, 0, 0] as [number, number, number]}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<InputRange
|
||||
label="Opacity"
|
||||
value={1}
|
||||
min={0}
|
||||
step={0.1}
|
||||
max={1}
|
||||
onChange={(value: number) => console.log(value)}
|
||||
key={"6"}
|
||||
/>
|
||||
|
||||
<div className="transformation-wrapper opacity">
|
||||
<div className="transformation-header">Layering</div>
|
||||
|
||||
<div className="layers-list">
|
||||
<button className="layer-move-btn">
|
||||
<LayeringBottomIcon />
|
||||
</button>
|
||||
<button className="layer-move-btn">
|
||||
<LayeringTopIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DecalProperties;
|
||||
@@ -3,27 +3,13 @@ import InputRange from "../../../ui/inputs/InputRange";
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
||||
import LabeledButton from "../../../ui/inputs/LabledButton";
|
||||
import {
|
||||
useAzimuth,
|
||||
useElevation,
|
||||
useLimitDistance,
|
||||
useRenderDistance,
|
||||
useResetCamera,
|
||||
useRoofVisibility,
|
||||
useSelectedWallItem,
|
||||
useShadows,
|
||||
useSocketStore,
|
||||
useTileDistance,
|
||||
useToggleView,
|
||||
useWallVisibility,
|
||||
} from "../../../../store/builder/store";
|
||||
import { useAzimuth, useElevation, useLimitDistance, useRenderDistance, useResetCamera, useRoofVisibility, useShadows, useSocketStore, useTileDistance, useToggleView, useWallVisibility } from "../../../../store/builder/store";
|
||||
import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
const GlobalProperties: React.FC = () => {
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||
const { roofVisibility, setRoofVisibility } = useRoofVisibility();
|
||||
const { wallVisibility, setWallVisibility } = useWallVisibility();
|
||||
const { shadows, setShadows } = useShadows();
|
||||
@@ -90,16 +76,6 @@ const GlobalProperties: React.FC = () => {
|
||||
setDistance(value);
|
||||
setRenderDistance(value);
|
||||
}
|
||||
function updateGridDistance(value: number) {
|
||||
setGridDistance(value);
|
||||
// setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||
// setPlaneValue({ height: value * 100, width: value * 100 });
|
||||
}
|
||||
function updatedGrid(value: number) {
|
||||
// console.log(" (value * 100) / 4 : ", (value * 100) / 4);
|
||||
setGridValue({ size: value * 100, divisions: (value * 100) / 4 });
|
||||
setPlaneValue({ height: value * 100, width: value * 100 });
|
||||
}
|
||||
|
||||
const updatedDist = async (value: number) => {
|
||||
setRenderDistance(value);
|
||||
@@ -145,7 +121,7 @@ const GlobalProperties: React.FC = () => {
|
||||
|
||||
setRoofVisibility(!roofVisibility); // Toggle roof visibility
|
||||
};
|
||||
// Function to toggle wall visibility
|
||||
|
||||
const changeWallVisibility = async () => {
|
||||
//using REST
|
||||
const data = await setEnvironment(
|
||||
@@ -203,20 +179,10 @@ const GlobalProperties: React.FC = () => {
|
||||
|
||||
const toggleResetCamera = () => {
|
||||
if (!toggleView) {
|
||||
setResetCamera(true); // Trigger reset camera action
|
||||
setResetCamera(true);
|
||||
}
|
||||
};
|
||||
|
||||
// function changeRenderDistance(e: any) {
|
||||
// if (parseInt(e.target.value) < 20) {
|
||||
// setRenderDistance(20);
|
||||
// } else if (parseInt(e.target.value) > 75) {
|
||||
// setRenderDistance(75);
|
||||
// } else {
|
||||
// setRenderDistance(parseInt(e.target.value));
|
||||
// }
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="global-properties-container">
|
||||
<section>
|
||||
@@ -253,16 +219,10 @@ const GlobalProperties: React.FC = () => {
|
||||
/>
|
||||
|
||||
<div className="split"></div>
|
||||
{/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */}
|
||||
<InputToggle
|
||||
inputKey="4"
|
||||
label="Limit Render Distance"
|
||||
value={limitDistance}
|
||||
// onClick={() => {
|
||||
// setLimitDistance(!limitDistance);
|
||||
// // setDistance(75);
|
||||
// // setRenderDistance(75);
|
||||
// }}
|
||||
onClick={async () => {
|
||||
await limitRenderDistance(); // Call the function here
|
||||
}}
|
||||
@@ -277,26 +237,6 @@ const GlobalProperties: React.FC = () => {
|
||||
onPointerUp={updatedDist}
|
||||
key={"6"}
|
||||
/>
|
||||
|
||||
{/* <div className="split"></div>
|
||||
<InputToggle
|
||||
inputKey="6"
|
||||
label="Display Grid"
|
||||
value={limitGridDistance}
|
||||
onClick={() => {
|
||||
setLimitGridDistance(!limitGridDistance);
|
||||
}}
|
||||
/>
|
||||
<InputRange
|
||||
label="Tile Distance"
|
||||
disabled={!limitGridDistance}
|
||||
value={gridDistance}
|
||||
key={"7"}
|
||||
min={1}
|
||||
max={5}
|
||||
onChange={(value: number) => updateGridDistance(value)}
|
||||
onPointerUp={updatedGrid}
|
||||
/> */}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,536 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import { ArrowIcon } from "../../../icons/ExportCommonIcons";
|
||||
|
||||
// image imports
|
||||
import Arc from "../../../../assets/image/aisleTypes/Arc.png";
|
||||
import Arrow from "../../../../assets/image/aisleTypes/Arrow.png";
|
||||
import Arrows from "../../../../assets/image/aisleTypes/Arrows.png";
|
||||
import Circle from "../../../../assets/image/aisleTypes/Circle.png";
|
||||
import Dashed from "../../../../assets/image/aisleTypes/Dashed.png";
|
||||
import Directional from "../../../../assets/image/aisleTypes/Directional.png";
|
||||
import Dotted from "../../../../assets/image/aisleTypes/Dotted.png";
|
||||
import Solid from "../../../../assets/image/aisleTypes/Solid.png";
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { aisleTextureList } from "./AisleProperties";
|
||||
|
||||
import { upsertAisleApi } from "../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||
|
||||
const SelectedAisleProperties: React.FC = () => {
|
||||
const [collapsePresets, setCollapsePresets] = useState(false);
|
||||
const [collapseTexture, setCollapseTexture] = useState(true);
|
||||
const { aisleStore } = useSceneContext();
|
||||
const { getAisleById, updateAisle, setDashedAisleProperties, setDottedAisleProperties, setArrowsAisleProperties, setArcAisleWidth, setColor } = aisleStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { socket } = useSocketStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectId } = useParams();
|
||||
const [selectedAisleData, setSelectedAisleData] = useState<Aisle | undefined>();
|
||||
|
||||
const { selectedAisle, setSelectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
const aisleData = getAisleById(selectedAisle?.aisleMesh?.uuid || "");
|
||||
setSelectedAisleData(aisleData);
|
||||
}, [selectedAisle, getAisleById]);
|
||||
|
||||
if (!selectedAisleData) return null;
|
||||
|
||||
const updateBackend = (updatedAisle: Aisle) => {
|
||||
if (updatedAisle && projectId) {
|
||||
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: updatedAisle.aisleUuid,
|
||||
points: updatedAisle.points,
|
||||
type: updatedAisle.type
|
||||
}
|
||||
|
||||
socket.emit('v1:model-aisle:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const aisleTypes: {
|
||||
name: string;
|
||||
type: AisleTypes;
|
||||
id: string;
|
||||
thumbnail: string;
|
||||
}[] = [
|
||||
{ name: "Solid", type: "solid-aisle", id: "1", thumbnail: Solid },
|
||||
{ name: "Dotted", type: "dotted-aisle", id: "2", thumbnail: Dotted },
|
||||
{ name: "Dashed", type: "dashed-aisle", id: "3", thumbnail: Dashed },
|
||||
{ name: "Arrow", type: "arrow-aisle", id: "4", thumbnail: Arrow },
|
||||
{ name: "Continuous Arrows", type: "arrows-aisle", id: "5", thumbnail: Arrows },
|
||||
{ name: "Directional", type: "junction-aisle", id: "6", thumbnail: Directional },
|
||||
{ name: "Arc", type: "arc-aisle", id: "7", thumbnail: Arc },
|
||||
{ name: "Circle", type: "circle-aisle", id: "8", thumbnail: Circle },
|
||||
];
|
||||
|
||||
const createAisleTypeObject = (newType: AisleTypes, currentType: AisleType): AisleType => {
|
||||
switch (newType) {
|
||||
case 'solid-aisle':
|
||||
return {
|
||||
aisleType: 'solid-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
||||
} as SolidAisle;
|
||||
|
||||
case 'dashed-aisle':
|
||||
return {
|
||||
aisleType: 'dashed-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
||||
dashLength: 'dashLength' in currentType ? (currentType as DashedAisle).dashLength : 0.5,
|
||||
gapLength: 'gapLength' in currentType ? (currentType as DashedAisle).gapLength : 0.3
|
||||
} as DashedAisle;
|
||||
|
||||
case 'dotted-aisle':
|
||||
return {
|
||||
aisleType: 'dotted-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
dotRadius: 'dotRadius' in currentType ? (currentType as DottedAisle).dotRadius : 0.1,
|
||||
gapLength: 'gapLength' in currentType ? (currentType as DottedAisle).gapLength : 0.3
|
||||
} as DottedAisle;
|
||||
|
||||
case 'arrow-aisle':
|
||||
return {
|
||||
aisleType: 'arrow-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
||||
} as ArrowAisle;
|
||||
|
||||
case 'arrows-aisle':
|
||||
return {
|
||||
aisleType: 'arrows-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
||||
aisleLength: 'aisleLength' in currentType ? (currentType as ArrowsAisle).aisleLength : 0.6,
|
||||
gapLength: 'gapLength' in currentType ? (currentType as ArrowsAisle).gapLength : 0.3
|
||||
} as ArrowsAisle;
|
||||
|
||||
case 'arc-aisle':
|
||||
return {
|
||||
aisleType: 'arc-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
||||
isFlipped: 'isFlipped' in currentType ? (currentType as ArcAisle).isFlipped : false
|
||||
} as ArcAisle;
|
||||
|
||||
case 'circle-aisle':
|
||||
return {
|
||||
aisleType: 'circle-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1
|
||||
} as CircleAisle;
|
||||
|
||||
case 'junction-aisle':
|
||||
return {
|
||||
aisleType: 'junction-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1,
|
||||
isFlipped: 'isFlipped' in currentType ? (currentType as JunctionAisle).isFlipped : false
|
||||
} as JunctionAisle;
|
||||
|
||||
default:
|
||||
return {
|
||||
aisleType: 'solid-aisle',
|
||||
aisleColor: currentType.aisleColor,
|
||||
aisleWidth: 0.1
|
||||
} as SolidAisle;
|
||||
}
|
||||
};
|
||||
|
||||
const handleAisleTypeChange = (newType: AisleTypes) => {
|
||||
if (!selectedAisle?.aisleData) return;
|
||||
const newAisleType = createAisleTypeObject(newType, selectedAisleData.type);
|
||||
|
||||
const updatedAisle = updateAisle(selectedAisleData.aisleUuid, {
|
||||
type: newAisleType
|
||||
});
|
||||
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: null });
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: newAisleType
|
||||
});
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
};
|
||||
|
||||
const handleColorChange = (value: AisleColors) => {
|
||||
const updatedAisle = setColor(selectedAisleData.aisleUuid, value);
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...selectedAisleData.type,
|
||||
aisleColor: value
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAisleWidthChange = (value: string) => {
|
||||
const width = parseFloat(value);
|
||||
if (!isNaN(width) && selectedAisleData.type.aisleType !== 'dotted-aisle') {
|
||||
const updatedAisle = updateAisle(selectedAisleData.aisleUuid, {
|
||||
type: {
|
||||
...selectedAisleData.type,
|
||||
aisleWidth: width
|
||||
}
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...selectedAisleData.type,
|
||||
aisleWidth: width
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDashLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length) && selectedAisleData.type.aisleType === 'dashed-aisle') {
|
||||
const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, {
|
||||
dashLength: length
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as DashedAisle),
|
||||
dashLength: length
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleGapLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length) && (selectedAisleData.type.aisleType === 'dashed-aisle' || selectedAisleData.type.aisleType === 'dotted-aisle' || selectedAisleData.type.aisleType === 'arrows-aisle')) {
|
||||
if (selectedAisleData.type.aisleType === 'dashed-aisle') {
|
||||
const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, {
|
||||
gapLength: length
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as DashedAisle),
|
||||
gapLength: length
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
} else if (selectedAisleData.type.aisleType === 'dotted-aisle') {
|
||||
const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, {
|
||||
gapLength: length
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as DottedAisle),
|
||||
gapLength: length
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
} else if (selectedAisleData.type.aisleType === 'arrows-aisle') {
|
||||
const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, {
|
||||
gapLength: length
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as ArrowsAisle),
|
||||
gapLength: length
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDotRadiusChange = (value: string) => {
|
||||
const radius = parseFloat(value);
|
||||
if (!isNaN(radius) && selectedAisleData.type.aisleType === 'dotted-aisle') {
|
||||
const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, {
|
||||
dotRadius: radius
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as DottedAisle),
|
||||
dotRadius: radius
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleAisleLengthChange = (value: string) => {
|
||||
const length = parseFloat(value);
|
||||
if (!isNaN(length) && selectedAisleData.type.aisleType === 'arrows-aisle') {
|
||||
const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, {
|
||||
aisleLength: length
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...(selectedAisleData.type as ArrowsAisle),
|
||||
aisleLength: length
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleIsFlippedChange = () => {
|
||||
if (selectedAisleData.type.aisleType === 'arc-aisle' || selectedAisleData.type.aisleType === 'junction-aisle') {
|
||||
const currentType = selectedAisleData.type as ArcAisle | JunctionAisle;
|
||||
const currentFlipped = currentType.isFlipped || false;
|
||||
const updatedAisle = setArcAisleWidth(selectedAisleData.aisleUuid, {
|
||||
isFlipped: !currentFlipped
|
||||
});
|
||||
|
||||
setSelectedAisleData({
|
||||
...selectedAisleData,
|
||||
type: {
|
||||
...currentType,
|
||||
isFlipped: !currentFlipped
|
||||
}
|
||||
})
|
||||
|
||||
if (updatedAisle) {
|
||||
updateBackend(updatedAisle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const renderAdvancedProperties = () => {
|
||||
switch (selectedAisleData.type.aisleType) {
|
||||
case 'dashed-aisle':
|
||||
const dashedType = selectedAisleData.type as DashedAisle;
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Dash Length"
|
||||
value={`${dashedType.dashLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleDashLengthChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${dashedType.gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case 'dotted-aisle':
|
||||
const dottedType = selectedAisleData.type as DottedAisle;
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Dot Radius"
|
||||
value={`${dottedType.dotRadius}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleDotRadiusChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${dottedType.gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case 'arrows-aisle':
|
||||
const arrowsType = selectedAisleData.type as ArrowsAisle;
|
||||
return (
|
||||
<>
|
||||
<InputWithDropDown
|
||||
label="Arrow Length"
|
||||
value={`${arrowsType.aisleLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleAisleLengthChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Gap Length"
|
||||
value={`${arrowsType.gapLength}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleGapLengthChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case 'junction-aisle':
|
||||
case 'arc-aisle':
|
||||
const flippedType = selectedAisleData.type as ArcAisle | JunctionAisle;
|
||||
return (
|
||||
<InputToggle
|
||||
inputKey="Flip Aisle"
|
||||
label="Flip Aisle"
|
||||
value={flippedType.isFlipped || false}
|
||||
onClick={handleIsFlippedChange}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="aisle-properties-container">
|
||||
<div className="header">Properties</div>
|
||||
|
||||
{/* Basic Properties */}
|
||||
<section>
|
||||
{selectedAisleData.type.aisleType !== 'dotted-aisle' &&
|
||||
<InputWithDropDown
|
||||
label="Aisle Width"
|
||||
value={`${selectedAisleData.type.aisleWidth || 0.5}`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={2}
|
||||
onChange={handleAisleWidthChange}
|
||||
/>
|
||||
}
|
||||
{renderAdvancedProperties()}
|
||||
</section>
|
||||
|
||||
{/* Presets */}
|
||||
<section>
|
||||
<button
|
||||
className="header"
|
||||
onClick={() => setCollapsePresets(!collapsePresets)}
|
||||
aria-expanded={!collapsePresets}
|
||||
>
|
||||
<div className="value">Presets</div>
|
||||
<div className="icon">
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
{!collapsePresets && (
|
||||
<div className="presets-list-container">
|
||||
{aisleTypes.map((val) => (
|
||||
<div className="preset-list" key={val.id}>
|
||||
<button
|
||||
className={`thumbnail ${selectedAisleData.type.aisleType === val.type ? "selected" : ""}`}
|
||||
title={val.name}
|
||||
onClick={() => handleAisleTypeChange(val.type)}
|
||||
>
|
||||
<img src={val.thumbnail} alt="" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Texture */}
|
||||
<section>
|
||||
<button
|
||||
className="header"
|
||||
onClick={() => setCollapseTexture(!collapseTexture)}
|
||||
aria-expanded={!collapseTexture}
|
||||
>
|
||||
<div className="value">Aisle Texture</div>
|
||||
<div className="icon" style={{ rotate: collapseTexture ? "" : "-90deg" }}>
|
||||
<ArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{collapseTexture && (
|
||||
<div className="aisle-texture-container">
|
||||
{aisleTextureList.map((val) => (
|
||||
<button
|
||||
key={val.id}
|
||||
title={val.brief || val.id}
|
||||
className={`aisle-list ${selectedAisleData.type.aisleColor === val.id ? "selected" : ""}`}
|
||||
onClick={() => handleColorChange(val.id)}
|
||||
aria-pressed={selectedAisleData.type.aisleColor === val.id}
|
||||
>
|
||||
<div
|
||||
className={`texture-display ${val.id}`}
|
||||
style={{ background: val.id }}
|
||||
>
|
||||
{val.texture}
|
||||
</div>
|
||||
<div className="aisle-color">{val.color}</div>
|
||||
<div className="aisle-brief">{`( ${val.brief} )`}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedAisleProperties;
|
||||
@@ -0,0 +1,194 @@
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import { LayeringBottomIcon, LayeringTopIcon } from "../../../icons/ExportCommonIcons";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
import InputRange from "../../../ui/inputs/InputRange";
|
||||
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
|
||||
const SelectedDecalProperties = () => {
|
||||
const { selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||
const { wallStore, floorStore } = useSceneContext();
|
||||
const { updateDecal: updateDecalInWall } = wallStore();
|
||||
const { updateDecal: updateDecalInFloor } = floorStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
const updateBackend = (updatedData: Wall | Floor) => {
|
||||
if ('wallUuid' in updatedData) {
|
||||
if (projectId && updatedData) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedData);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedData,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
} else if ('floorUuid' in updatedData) {
|
||||
if (projectId && updatedData) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedData);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedData,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleRotationChange = (value: number) => {
|
||||
if (!selectedDecal) return;
|
||||
const updatedDecal = { ...selectedDecal.decalData, decalRotation: value };
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
|
||||
const handleScaleChange = (value: number) => {
|
||||
if (!selectedDecal) return;
|
||||
const updatedDecal = { ...selectedDecal.decalData, decalScale: value };
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpacityChange = (value: number) => {
|
||||
if (!selectedDecal) return;
|
||||
const updatedDecal = { ...selectedDecal.decalData, decalOpacity: value };
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ('wallUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ('floorUuid' in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
}
|
||||
|
||||
const handleLayerChange = (direction: "up" | "down") => {
|
||||
if (!selectedDecal) return;
|
||||
|
||||
const position: [number, number, number] = [...(selectedDecal.decalData.decalPosition || [0, 0, 0]),];
|
||||
|
||||
if (direction === "up") {
|
||||
position[2] = Math.abs(position[2]);
|
||||
} else {
|
||||
position[2] = -Math.abs(position[2]);
|
||||
}
|
||||
|
||||
const updatedDecal: Decal = { ...selectedDecal.decalData, decalPosition: position, };
|
||||
|
||||
setSelectedDecal({ ...selectedDecal, decalData: updatedDecal });
|
||||
|
||||
if ("wallUuid" in selectedDecal.decalData.decalType) {
|
||||
const updatedWall = updateDecalInWall(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedWall) updateBackend(updatedWall);
|
||||
} else if ("floorUuid" in selectedDecal.decalData.decalType) {
|
||||
const updatedFloor = updateDecalInFloor(updatedDecal.decalUuid, updatedDecal);
|
||||
if (updatedFloor) updateBackend(updatedFloor);
|
||||
}
|
||||
};
|
||||
|
||||
if (!selectedDecal) return null;
|
||||
|
||||
return (
|
||||
<div className="decal-transformation-container">
|
||||
<div className="header">Decal Properties</div>
|
||||
<section>
|
||||
<InputRange
|
||||
label="Rotation"
|
||||
value={selectedDecal.decalData.decalRotation || 0}
|
||||
min={0}
|
||||
max={360}
|
||||
step={1}
|
||||
onChange={(value: number) => handleRotationChange(value)}
|
||||
/>
|
||||
|
||||
<InputRange
|
||||
label="Scale"
|
||||
value={selectedDecal.decalData.decalScale || 1}
|
||||
min={0.1}
|
||||
max={2}
|
||||
step={0.1}
|
||||
onChange={(value: number) => handleScaleChange(value)}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<InputRange
|
||||
label="Opacity"
|
||||
value={selectedDecal.decalData.decalOpacity || 1}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
max={1}
|
||||
onChange={(value: number) => handleOpacityChange(value)}
|
||||
/>
|
||||
|
||||
<div className="transformation-wrapper opacity">
|
||||
<div className="transformation-header">Layering</div>
|
||||
|
||||
<div className="layers-list">
|
||||
<button
|
||||
className="layer-move-btn"
|
||||
onClick={() => handleLayerChange("down")}
|
||||
>
|
||||
<LayeringBottomIcon />
|
||||
</button>
|
||||
<button
|
||||
className="layer-move-btn"
|
||||
onClick={() => handleLayerChange("up")}
|
||||
>
|
||||
<LayeringTopIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedDecalProperties;
|
||||
@@ -10,7 +10,7 @@ import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
import { materials } from "./FloorProperties";
|
||||
|
||||
// import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
|
||||
const SelectedFloorProperties = () => {
|
||||
const [depth, setDepth] = useState("");
|
||||
@@ -43,22 +43,25 @@ const SelectedFloorProperties = () => {
|
||||
if (!isNaN(parsed) && floor) {
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { floorDepth: parsed });
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -69,10 +72,40 @@ const SelectedFloorProperties = () => {
|
||||
if (!isNaN(parsed) && floor) {
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { bevelStrength: parsed });
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleIsBeveledToggle = () => {
|
||||
setIsBeveled(!isBeveled);
|
||||
if (!floor) return;
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { isBeveled: !floor.isBeveled });
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
@@ -87,30 +120,6 @@ const SelectedFloorProperties = () => {
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleIsBeveledToggle = () => {
|
||||
setIsBeveled(!isBeveled);
|
||||
if (!floor) return;
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { isBeveled: !floor.isBeveled });
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -119,22 +128,25 @@ const SelectedFloorProperties = () => {
|
||||
const key = activeSurface === "top" ? "topMaterial" : "sideMaterial";
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { [key]: material.textureId });
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
|
||||
// import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
|
||||
const SelectedWallProperties = () => {
|
||||
const [height, setHeight] = useState("");
|
||||
@@ -47,22 +47,25 @@ const SelectedWallProperties = () => {
|
||||
if (!isNaN(height) && wall) {
|
||||
const updatedWall = updateWall(wall.wallUuid, { wallHeight: height });
|
||||
if (updatedWall && projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -73,10 +76,41 @@ const SelectedWallProperties = () => {
|
||||
if (!isNaN(thickness) && wall) {
|
||||
const updatedWall = updateWall(wall.wallUuid, { wallThickness: thickness });
|
||||
if (updatedWall && projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
|
||||
if (!wall) return;
|
||||
|
||||
const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
|
||||
const updatedWall = updateWall(wall.wallUuid, updated);
|
||||
if (updatedWall && projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
@@ -93,31 +127,6 @@ const SelectedWallProperties = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
|
||||
if (!wall) return;
|
||||
|
||||
const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId })
|
||||
const updatedWall = updateWall(wall.wallUuid, updated);
|
||||
if (updatedWall && projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
};
|
||||
|
||||
if (!wall) return null;
|
||||
|
||||
const selectedMaterials = {
|
||||
|
||||
@@ -1,190 +1,225 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ClockThreeIcon, LocationPinIcon, TargetIcon } from '../../../../icons/ExportCommonIcons'
|
||||
import { useSceneContext } from '../../../../../modules/scene/sceneContext';
|
||||
import { useProductContext } from '../../../../../modules/simulation/products/productContext';
|
||||
import RenameInput from '../../../../ui/inputs/RenameInput';
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
ClockThreeIcon,
|
||||
LocationPinIcon,
|
||||
TargetIcon,
|
||||
} from "../../../../icons/ExportCommonIcons";
|
||||
import { useSceneContext } from "../../../../../modules/scene/sceneContext";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { useResourceManagementId } from "../../../../../store/builder/store";
|
||||
import { getAssetThumbnail } from "../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail";
|
||||
// import NavigateCatagory from '../NavigateCatagory'
|
||||
|
||||
const Hrm = () => {
|
||||
const [selectedCard, setSelectedCard] = useState(0);
|
||||
const [workers, setWorkers] = useState<any[]>([]);
|
||||
|
||||
const { productStore } = useSceneContext();
|
||||
const { products, getProductById } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct) {
|
||||
const productDetails = getProductById(selectedProduct.productUuid);
|
||||
const workerDetails = productDetails?.eventDatas || [];
|
||||
|
||||
const formattedWorkers = workerDetails
|
||||
.filter((worker: any) => worker.type === "human")
|
||||
.map((worker: any, index: number) => ({
|
||||
employee: {
|
||||
image: "",
|
||||
name: worker.modelName,
|
||||
employee_id: `HR-${204 + index}`,
|
||||
status: "Active",
|
||||
},
|
||||
task: {
|
||||
status: "Ongoing",
|
||||
title: worker.taskTitle || "No Task Assigned",
|
||||
location: {
|
||||
floor: worker.floor || 0,
|
||||
zone: worker.zone || "N/A"
|
||||
},
|
||||
planned_time_hours: worker.plannedTime || 0,
|
||||
time_spent_hours: worker.timeSpent || 0,
|
||||
total_tasks: worker.totalTasks || 0,
|
||||
completed_tasks: worker.completedTasks || 0
|
||||
},
|
||||
actions: [
|
||||
"Assign Task",
|
||||
"Reassign Task",
|
||||
"Pause",
|
||||
"Emergency Stop"
|
||||
],
|
||||
location: `Floor ${worker.floor || "-"} . Zone ${worker.zone || "-"}`
|
||||
}));
|
||||
|
||||
setWorkers(formattedWorkers);
|
||||
}
|
||||
}, [selectedProduct, getProductById]);
|
||||
|
||||
useEffect(() => {
|
||||
// console.log("Workers data updated:", workers);
|
||||
}, [workers]);
|
||||
|
||||
|
||||
|
||||
|
||||
// const employee_details = [
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "John Doe",
|
||||
// "employee_id": "HR-204",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Inspecting Machine X",
|
||||
// "location": {
|
||||
// "floor": 4,
|
||||
// "zone": "B"
|
||||
// },
|
||||
// "planned_time_hours": 6,
|
||||
// "time_spent_hours": 2,
|
||||
// "total_tasks": 12,
|
||||
// "completed_tasks": 3
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "Alice Smith",
|
||||
// "employee_id": "HR-205",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Calibrating Sensor Y",
|
||||
// "location": {
|
||||
// "floor": 2,
|
||||
// "zone": "A"
|
||||
// },
|
||||
// "planned_time_hours": 4,
|
||||
// "time_spent_hours": 1.5,
|
||||
// "total_tasks": 10,
|
||||
// "completed_tasks": 2
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "Michael Lee",
|
||||
// "employee_id": "HR-206",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Testing Conveyor Belt Z",
|
||||
// "location": {
|
||||
// "floor": 5,
|
||||
// "zone": "C"
|
||||
// },
|
||||
// "planned_time_hours": 5,
|
||||
// "time_spent_hours": 3,
|
||||
// "total_tasks": 8,
|
||||
// "completed_tasks": 5
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// ]
|
||||
function handleRenameWorker(newName: string) {
|
||||
// console.log('newName: ', newName);
|
||||
const [selectedCard, setSelectedCard] = useState(0);
|
||||
const [workers, setWorkers] = useState<any[]>([]);
|
||||
const { setResourceManagementId } = useResourceManagementId();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets: allAssets } = assetStore();
|
||||
|
||||
async function getAsset(assetId: string) {
|
||||
let thumbnail = await getAssetThumbnail(assetId);
|
||||
if (thumbnail.thumbnail) {
|
||||
let assetImage = thumbnail.thumbnail;
|
||||
return assetImage;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (allAssets.length > 0) {
|
||||
const fetchWorkers = async () => {
|
||||
const humans = allAssets.filter(
|
||||
(worker: any) => worker.eventData.type === "Human"
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <NavigateCatagory
|
||||
const formattedWorkers = await Promise.all(
|
||||
humans.map(async (worker: any, index: number) => {
|
||||
const assetImage = await getAsset(worker.assetId);
|
||||
|
||||
return {
|
||||
employee: {
|
||||
image: assetImage,
|
||||
name: worker.modelName,
|
||||
modelId: worker.modelUuid,
|
||||
employee_id: `HR-${204 + index}`,
|
||||
status: "Active",
|
||||
},
|
||||
task: {
|
||||
status: "Ongoing",
|
||||
title: worker.taskTitle ?? "No Task Assigned",
|
||||
location: {
|
||||
floor: worker.floor ?? 0,
|
||||
zone: worker.zone ?? "N/A",
|
||||
},
|
||||
planned_time_hours: worker.plannedTime ?? 0,
|
||||
time_spent_hours: worker.timeSpent ?? 0,
|
||||
total_tasks: worker.totalTasks ?? 0,
|
||||
completed_tasks: worker.completedTasks ?? 0,
|
||||
},
|
||||
actions: [
|
||||
"Assign Task",
|
||||
"Reassign Task",
|
||||
"Pause",
|
||||
"Emergency Stop",
|
||||
],
|
||||
location: `Floor ${worker.floor || "-"} . Zone ${
|
||||
worker.zone || "-"
|
||||
}`,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
setWorkers(formattedWorkers);
|
||||
};
|
||||
|
||||
fetchWorkers();
|
||||
}
|
||||
}, [allAssets]);
|
||||
|
||||
// const employee_details = [
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "John Doe",
|
||||
// "employee_id": "HR-204",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Inspecting Machine X",
|
||||
// "location": {
|
||||
// "floor": 4,
|
||||
// "zone": "B"
|
||||
// },
|
||||
// "planned_time_hours": 6,
|
||||
// "time_spent_hours": 2,
|
||||
// "total_tasks": 12,
|
||||
// "completed_tasks": 3
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "Alice Smith",
|
||||
// "employee_id": "HR-205",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Calibrating Sensor Y",
|
||||
// "location": {
|
||||
// "floor": 2,
|
||||
// "zone": "A"
|
||||
// },
|
||||
// "planned_time_hours": 4,
|
||||
// "time_spent_hours": 1.5,
|
||||
// "total_tasks": 10,
|
||||
// "completed_tasks": 2
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// {
|
||||
// "employee": {
|
||||
// image: "",
|
||||
// "name": "Michael Lee",
|
||||
// "employee_id": "HR-206",
|
||||
// "status": "Active",
|
||||
|
||||
// },
|
||||
// "task": {
|
||||
// "status": "Ongoing",
|
||||
// "title": "Testing Conveyor Belt Z",
|
||||
// "location": {
|
||||
// "floor": 5,
|
||||
// "zone": "C"
|
||||
// },
|
||||
// "planned_time_hours": 5,
|
||||
// "time_spent_hours": 3,
|
||||
// "total_tasks": 8,
|
||||
// "completed_tasks": 5
|
||||
// },
|
||||
// "actions": [
|
||||
// "Assign Task",
|
||||
// "Reassign Task",
|
||||
// "Pause",
|
||||
// "Emergency Stop"
|
||||
// ],
|
||||
// "location": "Floor 4 . Zone B"
|
||||
// },
|
||||
// ]
|
||||
function handleRenameWorker(newName: string) {}
|
||||
function handleHumanClick(employee: any) {
|
||||
if (employee.modelId) {
|
||||
setResourceManagementId(employee.modelId);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <NavigateCatagory
|
||||
category={["All People", "Technician", "Operator", "Supervisor", "Safety Officer"]}
|
||||
selectedCategory={selectedCategory}
|
||||
setSelectedCategory={setSelectedCategory}
|
||||
/> */}
|
||||
|
||||
<div className='hrm-container assetManagement-wrapper'>
|
||||
{workers.map((employee, index) => (
|
||||
<div
|
||||
className={`analysis-wrapper ${selectedCard === index ? "active" : ""}`}
|
||||
onClick={() => setSelectedCard(index)}
|
||||
key={index}
|
||||
>
|
||||
<header>
|
||||
<div className="user-details">
|
||||
<div className="user-image-wrapper">
|
||||
<img className='user-image' src={employee.employee.image} alt="" />
|
||||
<div className={`status ${employee.employee.status}`}></div>
|
||||
</div>
|
||||
<div className="details">
|
||||
{/* <div className="employee-name">{employee.employee.name}</div> */}
|
||||
<RenameInput value={employee.employee.name} onRename={handleRenameWorker} />
|
||||
<div className="employee-id">{employee.employee.employee_id}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hrm-container assetManagement-wrapper">
|
||||
{workers.map((employee, index) => (
|
||||
<div
|
||||
className={`analysis-wrapper ${
|
||||
selectedCard === index ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedCard(index)}
|
||||
key={index}
|
||||
>
|
||||
<header>
|
||||
<div className="user-details">
|
||||
<div className="user-image-wrapper">
|
||||
<img
|
||||
className="user-image"
|
||||
src={employee.employee.image}
|
||||
alt=""
|
||||
/>
|
||||
<div className={`status ${employee.employee.status}`}></div>
|
||||
</div>
|
||||
<div className="details">
|
||||
{/* <div className="employee-name">{employee.employee.name}</div> */}
|
||||
<RenameInput
|
||||
value={employee.employee.name}
|
||||
onRename={handleRenameWorker}
|
||||
/>
|
||||
<div className="employee-id">
|
||||
{employee.employee.employee_id}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="see-more">View more</div>
|
||||
</header>
|
||||
<div
|
||||
className="see-more"
|
||||
onClick={() => {
|
||||
handleHumanClick(employee.employee);
|
||||
}}
|
||||
>
|
||||
View in Scene
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="content">
|
||||
{/* <div className="task-info">
|
||||
<div className="content">
|
||||
{/* <div className="task-info">
|
||||
<div className="task-wrapper">
|
||||
<div className="task-label">
|
||||
<span className='label-icon'><ListTaskIcon /></span>
|
||||
@@ -205,17 +240,20 @@ const Hrm = () => {
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div className="task-stats">
|
||||
<div className="stat-item">
|
||||
<div className="task-stats">
|
||||
<div className="stat-item">
|
||||
<div className="stat-wrapper">
|
||||
<span className="stat-icon">
|
||||
<ClockThreeIcon />
|
||||
</span>
|
||||
<span>Planned time:</span>
|
||||
</div>
|
||||
|
||||
<div className="stat-wrapper">
|
||||
<span className="stat-icon"><ClockThreeIcon /></span>
|
||||
<span>Planned time:</span>
|
||||
</div>
|
||||
|
||||
<span className='stat-value'>{employee.task.planned_time_hours} hr</span>
|
||||
</div>
|
||||
{/* <div className="stat-item">
|
||||
<span className="stat-value">
|
||||
{employee.task.planned_time_hours} hr
|
||||
</span>
|
||||
</div>
|
||||
{/* <div className="stat-item">
|
||||
|
||||
<div className="stat-wrapper">
|
||||
<span className="stat-icon"><SlectedTickIcon /></span>
|
||||
@@ -233,39 +271,41 @@ const Hrm = () => {
|
||||
|
||||
<span className='stat-value'>{employee.task.time_spent_hours} hr</span>
|
||||
</div> */}
|
||||
<div className="stat-item">
|
||||
<div className="stat-item">
|
||||
<div className="stat-wrapper">
|
||||
<span className="stat-icon">
|
||||
<TargetIcon />
|
||||
</span>
|
||||
<span>Cost per hr:</span>
|
||||
</div>
|
||||
|
||||
<div className="stat-wrapper">
|
||||
<span className="stat-icon"><TargetIcon /></span>
|
||||
<span>Cost per hr:</span>
|
||||
</div>
|
||||
<span className="stat-value">
|
||||
{employee.task.completed_tasks}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span className='stat-value'>{employee.task.completed_tasks}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="location-wrapper">
|
||||
<div className="location-header">
|
||||
<div className="icon">
|
||||
<LocationPinIcon />
|
||||
</div>
|
||||
<div className="header">Location:</div>
|
||||
</div>
|
||||
<div className="location-value">{employee.location}</div>
|
||||
</div>
|
||||
<div className="task-actions">
|
||||
{/* <button className="btn btn-default">Assign Task</button>
|
||||
<button className="btn btn-default">Reassign Task</button> */}
|
||||
<button className="btn btn-default">Pause</button>
|
||||
<button className="btn btn-danger">Emergency Stop</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))}
|
||||
<div className="location-wrapper">
|
||||
<div className="location-header">
|
||||
<div className="icon">
|
||||
<LocationPinIcon />
|
||||
</div>
|
||||
<div className="header">Location:</div>
|
||||
</div>
|
||||
<div className="location-value">{employee.location}</div>
|
||||
</div>
|
||||
{/* <div className="task-actions">
|
||||
<button className="btn btn-default">Assign Task</button>
|
||||
<button className="btn btn-default">Reassign Task</button>
|
||||
<button className="btn btn-default">Pause</button>
|
||||
<button className="btn btn-danger">Emergency Stop</button>
|
||||
</div> */}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Hrm
|
||||
export default Hrm;
|
||||
|
||||
@@ -1,60 +1,70 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
// import NavigateCatagory from '../../NavigateCatagory'
|
||||
import { EyeIcon, ForkLiftIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons';
|
||||
import assetImage from "../../../../../../assets/image/asset-image.png"
|
||||
import { EyeIcon, KebabIcon, LocationPinIcon, RightHalfFillCircleIcon } from '../../../../../icons/ExportCommonIcons';
|
||||
import assetImageFallback from "../../../../../../assets/image/asset-image.png"
|
||||
import { useSceneContext } from '../../../../../../modules/scene/sceneContext';
|
||||
import { useProductContext } from '../../../../../../modules/simulation/products/productContext';
|
||||
import RenameInput from '../../../../../ui/inputs/RenameInput';
|
||||
import { useResourceManagementId } from '../../../../../../store/builder/store';
|
||||
import { getAssetThumbnail } from '../../../../../../services/factoryBuilder/asset/assets/getAssetThumbnail';
|
||||
import { TypeBasedAssetIcons } from '../../../../../icons/AssetTypeIcons';
|
||||
|
||||
const AssetManagement = () => {
|
||||
// const [selectedCategory, setSelectedCategory] = useState("All Assets");
|
||||
const [expandedAssetId, setExpandedAssetId] = useState<string | null>(null);
|
||||
const [assets, setAssets] = useState<any[]>([]);
|
||||
const { setResourceManagementId } = useResourceManagementId();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets: allAssets } = assetStore();
|
||||
|
||||
const { productStore } = useSceneContext();
|
||||
const { products, getProductById } = productStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
|
||||
async function getAsset(assetId: string) {
|
||||
let thumbnail = await getAssetThumbnail(assetId)
|
||||
if (thumbnail.thumbnail) {
|
||||
let assetImage = thumbnail.thumbnail ?? assetImageFallback;
|
||||
return assetImage;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct) {
|
||||
const productDetails = getProductById(selectedProduct.productUuid);
|
||||
const productAssets = productDetails?.eventDatas || [];
|
||||
const grouped: Record<string, any> = {};
|
||||
productAssets.forEach((asset: any) => {
|
||||
if (asset.type === "storageUnit" || asset.type === "human") return;
|
||||
if (!grouped[asset.modelName]) {
|
||||
grouped[asset.modelName] = {
|
||||
id: asset.assetId,
|
||||
name: asset.modelName,
|
||||
model: asset.modelCode || "N/A",
|
||||
status: asset.status || "Online",
|
||||
usageRate: asset.usageRate || 15,
|
||||
level: asset.level || "Level 1",
|
||||
image: assetImage,
|
||||
description: asset.description || "No description",
|
||||
cost: asset.cost || 0,
|
||||
count: 1,
|
||||
};
|
||||
} else {
|
||||
grouped[asset.modelName].count += 1;
|
||||
}
|
||||
});
|
||||
if (allAssets.length > 0) {
|
||||
const fetchAssets = async () => {
|
||||
const grouped: Record<string, any> = {};
|
||||
|
||||
setAssets(Object.values(grouped));
|
||||
// Use Promise.all to handle all async operations
|
||||
await Promise.all(allAssets.map(async (asset: any) => {
|
||||
|
||||
if (asset.eventData.type === "Storage" || asset.eventData.type === "Human") return;
|
||||
|
||||
const assetImage = await getAsset(asset.assetId);
|
||||
|
||||
if (!grouped[asset.assetId]) {
|
||||
//
|
||||
grouped[asset.assetId] = {
|
||||
id: asset.modelUuid,
|
||||
assetId: asset.assetId,
|
||||
name: asset.modelName,
|
||||
type: asset.eventData.type,
|
||||
model: asset.modelCode ?? "N/A",
|
||||
status: asset.status ?? "Online",
|
||||
usageRate: asset.usageRate ?? 15,
|
||||
level: asset.level ?? "Level 1",
|
||||
image: assetImage,
|
||||
description: asset.description ?? "No description",
|
||||
cost: asset.cost ?? 0,
|
||||
count: 1,
|
||||
};
|
||||
} else {
|
||||
grouped[asset.assetId].count += 1;
|
||||
}
|
||||
}));
|
||||
|
||||
setAssets(Object.values(grouped));
|
||||
}
|
||||
fetchAssets();
|
||||
}
|
||||
}, [selectedProduct]);
|
||||
}, [allAssets]);
|
||||
|
||||
function handleRenameAsset(newName: string) {
|
||||
// console.log('newName: ', newName);
|
||||
// if (expandedAssetId) {
|
||||
// setAssets(prevAssets =>
|
||||
// prevAssets.map(asset =>
|
||||
// asset.id === expandedAssetId ? { ...asset, name: newName } : asset
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -62,6 +72,10 @@ const AssetManagement = () => {
|
||||
|
||||
}, [assets]);
|
||||
|
||||
function handleAssetClick(id: string) {
|
||||
setResourceManagementId(id);
|
||||
}
|
||||
|
||||
// const dummyAssets = [
|
||||
// {
|
||||
// id: '1',
|
||||
@@ -105,35 +119,32 @@ const AssetManagement = () => {
|
||||
return (
|
||||
<>
|
||||
{/* <NavigateCatagory
|
||||
category={["All Assets", "Machines", "Workstation", "Vehicles"]}
|
||||
selectedCategory={selectedCategory}
|
||||
setSelectedCategory={setSelectedCategory}
|
||||
/> */}
|
||||
category={["All Assets", "Machines", "Workstation", "Vehicles"]}
|
||||
selectedCategory={selectedCategory}
|
||||
setSelectedCategory={setSelectedCategory}
|
||||
/> */}
|
||||
|
||||
<div className='assetManagement-container assetManagement-wrapper'>
|
||||
{assets.map((asset, index) => (
|
||||
<div className={`assetManagement-card-wrapper ${expandedAssetId === asset.id ? "openViewMore" : ""}`} key={index}>
|
||||
<header>
|
||||
<div className="header-wrapper">
|
||||
|
||||
{expandedAssetId === asset.id ?
|
||||
<>
|
||||
<div className="drop-icon" onClick={() => setExpandedAssetId(null)}>▾</div>
|
||||
<img className='asset-image' src={asset.image} alt="" />
|
||||
</>
|
||||
:
|
||||
<div className="icon"><ForkLiftIcon /></div>
|
||||
<div className="icon"><TypeBasedAssetIcons assetType={asset.type}/></div>
|
||||
}
|
||||
<div className="asset-details-container">
|
||||
<div className="asset-details">
|
||||
<div className="asset-details" >
|
||||
{/* <div className="asset-name">{asset.name}</div> */}
|
||||
<RenameInput value={asset.name} onRename={handleRenameAsset} />
|
||||
{asset.count !== 1 && <div>
|
||||
<span className="asset-id-label">x</span>
|
||||
<span className="asset-id">{asset.count}</span>
|
||||
</div>}
|
||||
|
||||
|
||||
<div className="asset-model">{asset.model}</div>
|
||||
</div>
|
||||
<div className="asset-status-wrapper">
|
||||
@@ -164,7 +175,7 @@ const AssetManagement = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="asset-estimate__view-button">
|
||||
<div className="asset-estimate__view-button" onClick={() => handleAssetClick(asset.id)}>
|
||||
<EyeIcon isClosed={false} />
|
||||
<div className="asset-estimate__view-text">View in Scene</div>
|
||||
</div>
|
||||
@@ -204,16 +215,10 @@ const AssetManagement = () => {
|
||||
<div className="value">{expandedAssetId === asset.id ? "View Less" : "View More"}</div>
|
||||
<div className="icon"><KebabIcon /></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
))}
|
||||
</div >
|
||||
</>
|
||||
|
||||
@@ -11,9 +11,9 @@ import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
|
||||
const VersionSaved = () => {
|
||||
const { versionHistory, addVersion, createNewVersion, setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { addVersion, createNewVersion, setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { setSelectedVersion } = selectedVersionStore();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
const [newName, setNewName] = useState(new Date().toLocaleString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
@@ -26,8 +26,6 @@ const VersionSaved = () => {
|
||||
const { projectId } = useParams();
|
||||
const { userId } = getUserData();
|
||||
|
||||
const latestVersion = versionHistory?.[0];
|
||||
|
||||
useEffect(() => {
|
||||
if (createNewVersion) {
|
||||
const defaultName = new Date().toLocaleString("en-US", {
|
||||
@@ -43,12 +41,12 @@ const VersionSaved = () => {
|
||||
}, [createNewVersion]);
|
||||
|
||||
const handleSave = () => {
|
||||
if (!latestVersion || !projectId) return;
|
||||
if (!selectedVersion || !projectId) return;
|
||||
|
||||
const updatedName = (newName.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
|
||||
const updatedDescription = (description.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
|
||||
const updatedName = (newName.trim() || selectedVersion.versionName) ?? selectedVersion.timeStamp;
|
||||
const updatedDescription = (description.trim() || selectedVersion.versionName) ?? selectedVersion.timeStamp;
|
||||
|
||||
createVersionApi(projectId, userId, latestVersion.versionId, updatedName, updatedDescription).then((data) => {
|
||||
createVersionApi(projectId, userId, selectedVersion.versionId, updatedName, updatedDescription).then((data) => {
|
||||
setSaveFinish(true);
|
||||
setCreateNewVersion(false);
|
||||
|
||||
@@ -84,7 +82,7 @@ const VersionSaved = () => {
|
||||
setCreateNewVersion(false);
|
||||
};
|
||||
|
||||
if (!latestVersion) return null;
|
||||
if (!selectedVersion) return null;
|
||||
|
||||
return (
|
||||
<div className={`versionSaved`}>
|
||||
@@ -105,7 +103,7 @@ const VersionSaved = () => {
|
||||
placeholder="Enter new version name"
|
||||
/>
|
||||
<div className="label">
|
||||
by @{latestVersion.createdBy}{" "}{new Date(latestVersion.timeStamp).toLocaleDateString("en-US", {
|
||||
by @{selectedVersion.createdBy}{" "}{new Date(selectedVersion.timeStamp).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
|
||||
@@ -3,7 +3,7 @@ import RenameInput from "./inputs/RenameInput";
|
||||
import { ArrowIcon } from "../icons/ExportCommonIcons";
|
||||
import MenuBar from "./menu/menu";
|
||||
import { ProjectIcon } from "../icons/HeaderIcons";
|
||||
import { useProjectName, useSocketStore } from "../../store/builder/store";
|
||||
import { useProjectName } from "../../store/builder/store";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { updateProject } from "../../services/dashboard/updateProject";
|
||||
@@ -14,7 +14,7 @@ const FileMenu: React.FC = () => {
|
||||
const containerRef = useRef<HTMLButtonElement>(null);
|
||||
let clickTimeout: NodeJS.Timeout | null = null;
|
||||
const { projectName, setProjectName } = useProjectName();
|
||||
const { dashBoardSocket } = useSocketStore();
|
||||
// const { dashBoardSocket } = useSocketStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization, email } = getUserData();
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
AsileIcon,
|
||||
CommentIcon,
|
||||
CursorIcon,
|
||||
DeleteIcon,
|
||||
FloorIcon,
|
||||
FreeMoveIcon,
|
||||
MeasureToolIcon,
|
||||
PenIcon,
|
||||
PlayIcon,
|
||||
SaveTemplateIcon,
|
||||
WallIcon,
|
||||
ZoneIcon,
|
||||
AsileIcon,
|
||||
CommentIcon,
|
||||
CursorIcon,
|
||||
DeleteIcon,
|
||||
FloorIcon,
|
||||
FreeMoveIcon,
|
||||
MeasureToolIcon,
|
||||
PenIcon,
|
||||
PlayIcon,
|
||||
SaveTemplateIcon,
|
||||
WallIcon,
|
||||
ZoneIcon,
|
||||
} from "../icons/ExportToolsIcons";
|
||||
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
|
||||
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
||||
@@ -20,414 +20,417 @@ import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
||||
import useTemplateStore from "../../store/useTemplateStore";
|
||||
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
||||
import {
|
||||
useActiveTool,
|
||||
useAddAction,
|
||||
useSelectedWallItem,
|
||||
useSocketStore,
|
||||
useToggleView,
|
||||
useToolMode,
|
||||
useActiveSubTool,
|
||||
useShortcutStore,
|
||||
useActiveTool,
|
||||
useAddAction,
|
||||
useSocketStore,
|
||||
useToggleView,
|
||||
useToolMode,
|
||||
useActiveSubTool,
|
||||
useShortcutStore,
|
||||
} from "../../store/builder/store";
|
||||
import { useToggleStore } from "../../store/useUIToggleStore";
|
||||
import {
|
||||
use3DWidget,
|
||||
useFloatingWidget,
|
||||
use3DWidget,
|
||||
useFloatingWidget,
|
||||
} from "../../store/visualization/useDroppedObjectsStore";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../modules/builder/version/versionContext";
|
||||
import { MoveIcon, RotateIcon } from "../icons/ShortcutIcons";
|
||||
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
||||
|
||||
// Utility component
|
||||
const ToolButton = ({
|
||||
toolKey,
|
||||
toolId,
|
||||
icon: Icon,
|
||||
active,
|
||||
onClick,
|
||||
tooltip,
|
||||
toolKey,
|
||||
toolId,
|
||||
icon: Icon,
|
||||
active,
|
||||
onClick,
|
||||
tooltip,
|
||||
}: any) => (
|
||||
<button
|
||||
key={toolKey} // used in rendering list
|
||||
id={toolId}
|
||||
className={`tool-button ${active ? "active" : ""}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="tooltip">{tooltip}</div>
|
||||
<div className="tool" id={toolId}>
|
||||
<Icon isActive={active} />
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
key={toolKey} // used in rendering list
|
||||
id={toolId}
|
||||
className={`tool-button ${active ? "active" : ""}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="tooltip">{tooltip}</div>
|
||||
<div className="tool" id={toolId}>
|
||||
<Icon isActive={active} />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
|
||||
const Tools: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
|
||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||
const { showShortcuts } = useShortcutStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleThreeD, setToggleThreeD } = useThreeDStore();
|
||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||
const { showShortcuts } = useShortcutStore();
|
||||
const { activeTool, setActiveTool, setToolMode, setAddAction } = useStoreHooks();
|
||||
const { setSelectedWallAsset } = useBuilderStore();
|
||||
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
const { setToggleView, toggleView } = useToggleView();
|
||||
|
||||
const { activeTool, setActiveTool, setToolMode, setAddAction } =
|
||||
useStoreHooks();
|
||||
const { addTemplate, templates } = useTemplateStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { floatingWidget } = useFloatingWidget();
|
||||
const { widgets3D } = use3DWidget();
|
||||
|
||||
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
|
||||
const { setSelectedWallItem } = useSelectedWallItem();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
const { setToggleView, toggleView } = useToggleView();
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const { addTemplate, templates } = useTemplateStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { floatingWidget } = useFloatingWidget();
|
||||
const { widgets3D } = use3DWidget();
|
||||
const dropdownRef = useRef<HTMLButtonElement>(null);
|
||||
const [openDrop, setOpenDrop] = useState(false);
|
||||
|
||||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
// 1. Set UI toggles on initial render
|
||||
useEffect(() => {
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft") !== "false",
|
||||
localStorage.getItem("navBarUiRight") !== "false"
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const dropdownRef = useRef<HTMLButtonElement>(null);
|
||||
const [openDrop, setOpenDrop] = useState(false);
|
||||
// 2. Update tool based on subtool and module
|
||||
useEffect(() => {
|
||||
setActiveTool(activeSubTool);
|
||||
setActiveSubTool(activeSubTool);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeModule]);
|
||||
|
||||
// 1. Set UI toggles on initial render
|
||||
useEffect(() => {
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft") !== "false",
|
||||
localStorage.getItem("navBarUiRight") !== "false"
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
// 3. Update tools behavior based on selected tool and view mode
|
||||
useEffect(() => {
|
||||
resetTools();
|
||||
updateToolBehavior(activeTool, toggleView);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeTool, toggleView]);
|
||||
|
||||
// 2. Update tool based on subtool and module
|
||||
useEffect(() => {
|
||||
setActiveTool(activeSubTool);
|
||||
setActiveSubTool(activeSubTool);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeModule]);
|
||||
// 4. Dropdown auto-close
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(e.target as Node)
|
||||
) {
|
||||
setOpenDrop(false);
|
||||
}
|
||||
};
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
// 3. Update tools behavior based on selected tool and view mode
|
||||
useEffect(() => {
|
||||
resetTools();
|
||||
updateToolBehavior(activeTool, toggleView);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [activeTool, toggleView]);
|
||||
|
||||
// 4. Dropdown auto-close
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e: MouseEvent) => {
|
||||
if (
|
||||
dropdownRef.current &&
|
||||
!dropdownRef.current.contains(e.target as Node)
|
||||
) {
|
||||
setOpenDrop(false);
|
||||
}
|
||||
const resetTools = () => {
|
||||
setToolMode(null);
|
||||
setAddAction(null);
|
||||
};
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
const resetTools = () => {
|
||||
setToolMode(null);
|
||||
setAddAction(null);
|
||||
};
|
||||
|
||||
const updateToolBehavior = (tool: string, is2D: boolean) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
is2D ? setToolMode("move") : setToolMode("cursor");
|
||||
break;
|
||||
case "draw-wall":
|
||||
is2D && setToolMode("Wall");
|
||||
break;
|
||||
case "draw-aisle":
|
||||
is2D && setToolMode("Aisle");
|
||||
break;
|
||||
case "draw-zone":
|
||||
is2D && setToolMode("Zone");
|
||||
break;
|
||||
case "draw-floor":
|
||||
is2D && setToolMode("Floor");
|
||||
break;
|
||||
case "measure":
|
||||
setToolMode("MeasurementScale");
|
||||
break;
|
||||
case "Add pillar":
|
||||
if (!is2D) setAddAction("Pillar");
|
||||
break;
|
||||
case "delete":
|
||||
is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const toggle2D3D = () => {
|
||||
const toggleTo2D = toggleView;
|
||||
setToggleView(!toggleTo2D);
|
||||
setToggleThreeD(toggleTo2D);
|
||||
setToggleUI(toggleTo2D, toggleTo2D);
|
||||
if (toggleTo2D) {
|
||||
setSelectedWallItem(null);
|
||||
setAddAction(null);
|
||||
}
|
||||
setActiveTool("cursor");
|
||||
setActiveSubTool("cursor");
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft") !== "false",
|
||||
localStorage.getItem("navBarUiRight") !== "false"
|
||||
);
|
||||
};
|
||||
|
||||
const renderBuilderTools = () => (
|
||||
<>
|
||||
{!toggleThreeD && (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="drawWall"
|
||||
icon={WallIcon}
|
||||
tooltip="draw wall (q)"
|
||||
active={activeTool === "draw-wall"}
|
||||
onClick={() => setActiveTool("draw-wall")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawZone"
|
||||
icon={ZoneIcon}
|
||||
tooltip="draw zone (e)"
|
||||
active={activeTool === "draw-zone"}
|
||||
onClick={() => setActiveTool("draw-zone")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawAisle"
|
||||
icon={AsileIcon}
|
||||
tooltip="draw aisle (r)"
|
||||
active={activeTool === "draw-aisle"}
|
||||
onClick={() => setActiveTool("draw-aisle")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawFloor"
|
||||
icon={FloorIcon}
|
||||
tooltip="draw floor (t)"
|
||||
active={activeTool === "draw-floor"}
|
||||
onClick={() => setActiveTool("draw-floor")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="measureScale"
|
||||
icon={MeasureToolIcon}
|
||||
tooltip="measure scale (m)"
|
||||
active={activeTool === "measure"}
|
||||
onClick={() => setActiveTool("measure")}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const renderSimulationTools = () => (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="pen"
|
||||
icon={PenIcon}
|
||||
tooltip="pen"
|
||||
active={activeTool === "pen"}
|
||||
onClick={() => setActiveTool("pen")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const renderVisualizationTools = () => (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="saveTemplate"
|
||||
icon={SaveTemplateIcon}
|
||||
tooltip="save template"
|
||||
active={false}
|
||||
onClick={() =>
|
||||
handleSaveTemplate({
|
||||
addTemplate,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
selectedZone,
|
||||
templates,
|
||||
visualizationSocket,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
})
|
||||
const updateToolBehavior = (tool: string, is2D: boolean) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
is2D ? setToolMode("move") : setToolMode("cursor");
|
||||
break;
|
||||
case "draw-wall":
|
||||
is2D && setToolMode("Wall");
|
||||
break;
|
||||
case "draw-aisle":
|
||||
is2D && setToolMode("Aisle");
|
||||
break;
|
||||
case "draw-zone":
|
||||
is2D && setToolMode("Zone");
|
||||
break;
|
||||
case "draw-floor":
|
||||
is2D && setToolMode("Floor");
|
||||
break;
|
||||
case "move":
|
||||
if (!is2D) setToolMode("Move-Asset");
|
||||
break;
|
||||
case "rotate":
|
||||
if (!is2D) setToolMode("Rotate-Asset");
|
||||
break;
|
||||
case "measure":
|
||||
setToolMode("MeasurementScale");
|
||||
break;
|
||||
case "Add pillar":
|
||||
if (!is2D) setAddAction("Pillar");
|
||||
break;
|
||||
case "delete":
|
||||
is2D ? setToolMode("2D-Delete") : setToolMode("3D-Delete");
|
||||
break;
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderModeSwitcher = () => (
|
||||
<button
|
||||
id="toggle-threed-button"
|
||||
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""}`}
|
||||
onClick={toggle2D3D}
|
||||
>
|
||||
<div className="tooltip">toggle view (tab)</div>
|
||||
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>2d</div>
|
||||
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>3d</div>
|
||||
</button>
|
||||
);
|
||||
const toggle2D3D = () => {
|
||||
const toggleTo2D = toggleView;
|
||||
setToggleView(!toggleTo2D);
|
||||
setToggleThreeD(toggleTo2D);
|
||||
setToggleUI(toggleTo2D, toggleTo2D);
|
||||
if (toggleTo2D) {
|
||||
setSelectedWallAsset(null);
|
||||
setAddAction(null);
|
||||
}
|
||||
setActiveTool("cursor");
|
||||
setActiveSubTool("cursor");
|
||||
setToggleUI(
|
||||
localStorage.getItem("navBarUiLeft") !== "false",
|
||||
localStorage.getItem("navBarUiRight") !== "false"
|
||||
);
|
||||
};
|
||||
|
||||
const getIconByTool = (tool: string) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
return CursorIcon;
|
||||
case "free-hand":
|
||||
return FreeMoveIcon;
|
||||
case "delete":
|
||||
return DeleteIcon;
|
||||
case "move":
|
||||
return MoveIcon;
|
||||
case "rotate":
|
||||
return RotateIcon;
|
||||
default:
|
||||
return CursorIcon;
|
||||
}
|
||||
};
|
||||
|
||||
const getTooltipShortcut = (tool: string) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
return "v";
|
||||
case "free-hand":
|
||||
return "h";
|
||||
case "delete":
|
||||
return "x";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const getIconComponent = (option: string) => {
|
||||
switch (option) {
|
||||
case "cursor":
|
||||
return <CursorIcon isActive={false} />;
|
||||
case "free-hand":
|
||||
return <FreeMoveIcon isActive={false} />;
|
||||
case "delete":
|
||||
return <DeleteIcon isActive={false} />;
|
||||
case "move":
|
||||
return <MoveIcon />;
|
||||
case "rotate":
|
||||
return <RotateIcon />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`tools-container ${showShortcuts ? "visible" : ""}`}>
|
||||
<div className="activeDropicon">
|
||||
{/* Tool Picker (cursor, delete, etc.) */}
|
||||
{["cursor", "free-hand", "delete"].map(
|
||||
(tool) =>
|
||||
activeSubTool === tool && (
|
||||
<ToolButton
|
||||
key={tool}
|
||||
toolId={tool}
|
||||
icon={getIconByTool(tool)}
|
||||
tooltip={`${tool} (${getTooltipShortcut(tool)})`}
|
||||
active={activeTool === tool}
|
||||
onClick={() => setActiveTool(tool)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{/* Dropdown Menu */}
|
||||
{activeModule !== "visualization" && (
|
||||
<button
|
||||
id="drop-down-button"
|
||||
title="drop-down"
|
||||
className="drop-down-option-button"
|
||||
ref={dropdownRef}
|
||||
onClick={() => setOpenDrop(!openDrop)}
|
||||
>
|
||||
<ArrowIcon />
|
||||
{openDrop && (
|
||||
<div className="drop-down-container">
|
||||
{["cursor", "free-hand", "delete"].map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
id={`${option}-tool`}
|
||||
className="option-list"
|
||||
onClick={() => {
|
||||
setActiveTool(option);
|
||||
setActiveSubTool(option);
|
||||
setOpenDrop(false);
|
||||
}}
|
||||
>
|
||||
<div className="active-option">
|
||||
{activeSubTool === option && <TickIcon />}
|
||||
</div>
|
||||
{getIconComponent(option)}
|
||||
<div className="option">{option}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
const renderBuilderTools = () => (
|
||||
<>
|
||||
{!toggleThreeD && (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="drawWall"
|
||||
icon={WallIcon}
|
||||
tooltip="draw wall (q)"
|
||||
active={activeTool === "draw-wall"}
|
||||
onClick={() => setActiveTool("draw-wall")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawZone"
|
||||
icon={ZoneIcon}
|
||||
tooltip="draw zone (e)"
|
||||
active={activeTool === "draw-zone"}
|
||||
onClick={() => setActiveTool("draw-zone")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawAisle"
|
||||
icon={AsileIcon}
|
||||
tooltip="draw aisle (r)"
|
||||
active={activeTool === "draw-aisle"}
|
||||
onClick={() => setActiveTool("draw-aisle")}
|
||||
/>
|
||||
<ToolButton
|
||||
toolId="drawFloor"
|
||||
icon={FloorIcon}
|
||||
tooltip="draw floor (t)"
|
||||
active={activeTool === "draw-floor"}
|
||||
onClick={() => setActiveTool("draw-floor")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{activeModule !== "visualization" && (
|
||||
<>
|
||||
<div className="split"></div>
|
||||
<div className="transform-tools">
|
||||
{["move", "rotate"].map((tool) => (
|
||||
<ToolButton
|
||||
key={tool}
|
||||
toolId={tool}
|
||||
icon={getIconByTool(tool)}
|
||||
tooltip={`${tool}`}
|
||||
active={activeTool === tool}
|
||||
onClick={() => setActiveTool(tool)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="measureScale"
|
||||
icon={MeasureToolIcon}
|
||||
tooltip="measure scale (m)"
|
||||
active={activeTool === "measure"}
|
||||
onClick={() => setActiveTool("measure")}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
);
|
||||
|
||||
<div className="split"></div>
|
||||
{activeModule === "builder" && renderBuilderTools()}
|
||||
{activeModule === "simulation" && renderSimulationTools()}
|
||||
{activeModule === "visualization" && renderVisualizationTools()}
|
||||
const renderSimulationTools = () => (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="pen"
|
||||
icon={PenIcon}
|
||||
tooltip="pen"
|
||||
active={activeTool === "pen"}
|
||||
onClick={() => setActiveTool("pen")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
<div className="split"></div>
|
||||
<div className="general-options">
|
||||
<ToolButton
|
||||
toolId="comment"
|
||||
icon={CommentIcon}
|
||||
tooltip="comment"
|
||||
active={activeTool === "comment"}
|
||||
onClick={() => setActiveTool("comment")}
|
||||
/>
|
||||
{toggleThreeD && (
|
||||
<ToolButton
|
||||
toolId="play"
|
||||
icon={PlayIcon}
|
||||
tooltip="play (ctrl + p)"
|
||||
active={activeTool === "play"}
|
||||
onClick={() => setIsPlaying(!isPlaying)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
const renderVisualizationTools = () => (
|
||||
<div className="draw-tools">
|
||||
<ToolButton
|
||||
toolId="saveTemplate"
|
||||
icon={SaveTemplateIcon}
|
||||
tooltip="save template"
|
||||
active={false}
|
||||
onClick={() =>
|
||||
handleSaveTemplate({
|
||||
addTemplate,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
selectedZone,
|
||||
templates,
|
||||
visualizationSocket,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
{activeModule === "builder" && (
|
||||
<>
|
||||
<div className="split"></div>
|
||||
{renderModeSwitcher()}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const renderModeSwitcher = () => (
|
||||
<button
|
||||
id="toggle-threed-button"
|
||||
className={`toggle-threed-button${toggleThreeD ? " toggled" : ""}`}
|
||||
onClick={toggle2D3D}
|
||||
>
|
||||
<div className="tooltip">toggle view (tab)</div>
|
||||
<div className={`toggle-option${!toggleThreeD ? " active" : ""}`}>2d</div>
|
||||
<div className={`toggle-option${toggleThreeD ? " active" : ""}`}>3d</div>
|
||||
</button>
|
||||
);
|
||||
|
||||
const getIconByTool = (tool: string) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
return CursorIcon;
|
||||
case "free-hand":
|
||||
return FreeMoveIcon;
|
||||
case "delete":
|
||||
return DeleteIcon;
|
||||
case "move":
|
||||
return MoveIcon;
|
||||
case "rotate":
|
||||
return RotateIcon;
|
||||
default:
|
||||
return CursorIcon;
|
||||
}
|
||||
};
|
||||
|
||||
const getTooltipShortcut = (tool: string) => {
|
||||
switch (tool) {
|
||||
case "cursor":
|
||||
return "v";
|
||||
case "free-hand":
|
||||
return "h";
|
||||
case "delete":
|
||||
return "x";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const getIconComponent = (option: string) => {
|
||||
switch (option) {
|
||||
case "cursor":
|
||||
return <CursorIcon isActive={false} />;
|
||||
case "free-hand":
|
||||
return <FreeMoveIcon isActive={false} />;
|
||||
case "delete":
|
||||
return <DeleteIcon isActive={false} />;
|
||||
case "move":
|
||||
return <MoveIcon />;
|
||||
case "rotate":
|
||||
return <RotateIcon />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`tools-container ${showShortcuts ? "visible" : ""}`}>
|
||||
<div className="activeDropicon">
|
||||
{/* Tool Picker (cursor, delete, etc.) */}
|
||||
{["cursor", "free-hand", "delete"].map(
|
||||
(tool) =>
|
||||
activeSubTool === tool && (
|
||||
<ToolButton
|
||||
key={tool}
|
||||
toolId={tool}
|
||||
icon={getIconByTool(tool)}
|
||||
tooltip={`${tool} (${getTooltipShortcut(tool)})`}
|
||||
active={activeTool === tool}
|
||||
onClick={() => setActiveTool(tool)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{/* Dropdown Menu */}
|
||||
{activeModule !== "visualization" && (
|
||||
<button
|
||||
id="drop-down-button"
|
||||
title="drop-down"
|
||||
className="drop-down-option-button"
|
||||
ref={dropdownRef}
|
||||
onClick={() => setOpenDrop(!openDrop)}
|
||||
>
|
||||
<ArrowIcon />
|
||||
{openDrop && (
|
||||
<div className="drop-down-container">
|
||||
{["cursor", "free-hand", "delete"].map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
id={`${option}-tool`}
|
||||
className="option-list"
|
||||
onClick={() => {
|
||||
setActiveTool(option);
|
||||
setActiveSubTool(option);
|
||||
setOpenDrop(false);
|
||||
}}
|
||||
>
|
||||
<div className="active-option">
|
||||
{activeSubTool === option && <TickIcon />}
|
||||
</div>
|
||||
{getIconComponent(option)}
|
||||
<div className="option">{option}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{toggleThreeD && activeModule !== "visualization" && (
|
||||
<>
|
||||
<div className="split"></div>
|
||||
<div className="transform-tools">
|
||||
{["move", "rotate"].map((tool) => (
|
||||
<ToolButton
|
||||
key={tool}
|
||||
toolId={tool}
|
||||
icon={getIconByTool(tool)}
|
||||
tooltip={`${tool}`}
|
||||
active={activeTool === tool}
|
||||
onClick={() => setActiveTool(tool)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="split"></div>
|
||||
{activeModule === "builder" && renderBuilderTools()}
|
||||
{activeModule === "simulation" && renderSimulationTools()}
|
||||
{activeModule === "visualization" && renderVisualizationTools()}
|
||||
|
||||
<div className="split"></div>
|
||||
<div className="general-options">
|
||||
<ToolButton
|
||||
toolId="comment"
|
||||
icon={CommentIcon}
|
||||
tooltip="comment"
|
||||
active={activeTool === "comment"}
|
||||
onClick={() => setActiveTool("comment")}
|
||||
/>
|
||||
{toggleThreeD && (
|
||||
<ToolButton
|
||||
toolId="play"
|
||||
icon={PlayIcon}
|
||||
tooltip="play (ctrl + p)"
|
||||
active={activeTool === "play"}
|
||||
onClick={() => setIsPlaying(!isPlaying)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{activeModule === "builder" && (
|
||||
<>
|
||||
<div className="split"></div>
|
||||
{renderModeSwitcher()}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Extracted common store logic
|
||||
const useStoreHooks = () => {
|
||||
return {
|
||||
...useActiveTool(),
|
||||
...useToolMode(),
|
||||
...useAddAction(),
|
||||
};
|
||||
return {
|
||||
...useActiveTool(),
|
||||
...useToolMode(),
|
||||
...useAddAction(),
|
||||
};
|
||||
};
|
||||
|
||||
export default Tools;
|
||||
|
||||
@@ -65,32 +65,34 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
|
||||
if (isEditableThread && editedThread) {
|
||||
try {
|
||||
// const editThreadTitle = await editThreadTitleApi(projectId, (val as CommentSchema).threadId, value, selectedVersion?.versionId || "")
|
||||
// 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 || selectedComment.threadId,
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
if (!threadSocket?.active) {
|
||||
const editThreadTitle = await editThreadTitleApi(projectId, (val as CommentSchema).threadId, value, selectedVersion?.versionId || "")
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
const threadEdit = {
|
||||
projectId,
|
||||
userId,
|
||||
threadTitle: value,
|
||||
organization,
|
||||
threadId: (val as CommentSchema).threadId || selectedComment.threadId,
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
|
||||
threadSocket.emit('v1:thread:updateTitle', threadEdit)
|
||||
threadSocket.emit('v1:thread:updateTitle', threadEdit)
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
} else {
|
||||
@@ -277,7 +279,7 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
<div className="message">
|
||||
{"comment" in val ? val.comment : val.threadTitle}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div >
|
||||
)}
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
useLeftData,
|
||||
useTopData,
|
||||
} from "../../../store/visualization/useZone3DWidgetStore";
|
||||
import { useRenameModeStore } from "../../../store/builder/store";
|
||||
|
||||
type RenameTooltipProps = {
|
||||
name: string;
|
||||
@@ -20,6 +19,7 @@ const RenameTooltip: React.FC<RenameTooltipProps> = ({ name, onSubmit }) => {
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
onSubmit(value.trim());
|
||||
echo.info(`Selected Object has been renamed to ${value.trim()}`);
|
||||
setTop(0);
|
||||
setLeft(0);
|
||||
};
|
||||
|
||||
@@ -12,7 +12,12 @@ interface RenameInputProps {
|
||||
canEdit?: boolean;
|
||||
}
|
||||
|
||||
const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplicate, canEdit = true }) => {
|
||||
const RenameInput: React.FC<RenameInputProps> = ({
|
||||
value,
|
||||
onRename,
|
||||
checkDuplicate,
|
||||
canEdit = true,
|
||||
}) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [text, setText] = useState(value);
|
||||
const [isDuplicate, setIsDuplicate] = useState(false);
|
||||
@@ -36,10 +41,10 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplica
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
|
||||
if (isDuplicate) return
|
||||
if (isDuplicate) return;
|
||||
setIsEditing(false);
|
||||
if (onRename && !isDuplicate) {
|
||||
echo.info(`Selected Object has been renamed to ${text}`)
|
||||
onRename(text);
|
||||
}
|
||||
};
|
||||
@@ -52,6 +57,7 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplica
|
||||
if (e.key === "Enter" && !isDuplicate) {
|
||||
setIsEditing(false);
|
||||
if (onRename) {
|
||||
echo.info(`Selected Object has been renamed to ${text}`)
|
||||
onRename(text);
|
||||
}
|
||||
}
|
||||
@@ -80,4 +86,4 @@ const RenameInput: React.FC<RenameInputProps> = ({ value, onRename, checkDuplica
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RenameInput
|
||||
export default RenameInput;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import React, { ChangeEvent, useState } from "react";
|
||||
import React, { ChangeEvent, useEffect, useState } from "react";
|
||||
import { CloseIcon, SearchIcon } from "../../icons/ExportCommonIcons";
|
||||
|
||||
interface SearchProps {
|
||||
value?: string; // The current value of the search input
|
||||
value?: string | null; // The current value of the search input
|
||||
placeholder?: string; // Placeholder text for the input
|
||||
onChange: (value: string) => void; // Callback function to handle input changes
|
||||
debounced?: boolean; // New prop: whether to debounce onChange
|
||||
}
|
||||
|
||||
const Search: React.FC<SearchProps> = ({
|
||||
value = "",
|
||||
placeholder = "Search",
|
||||
onChange,
|
||||
debounced = false, // Default false
|
||||
}) => {
|
||||
// State to track the input value and focus status
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
@@ -19,28 +21,49 @@ const Search: React.FC<SearchProps> = ({
|
||||
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
setInputValue(newValue);
|
||||
onChange(newValue); // Call the onChange prop with the new value
|
||||
|
||||
if (!debounced) {
|
||||
onChange(newValue); // Immediate call if not debounced
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (value === null) {
|
||||
setInputValue("");
|
||||
handleBlur();
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
// Handle debounced effect
|
||||
useEffect(() => {
|
||||
if (!debounced) return;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
onChange(inputValue ?? "");
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [inputValue, debounced, onChange]);
|
||||
|
||||
const handleClear = () => {
|
||||
console.warn("Search field cleared.");
|
||||
setInputValue("");
|
||||
onChange(""); // Clear the input value
|
||||
onChange(""); // Clear immediately
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
setIsFocused(true); // Set focus state to true
|
||||
setIsFocused(true);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
setIsFocused(false); // Set focus state to false
|
||||
setIsFocused(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="search-wrapper">
|
||||
<div
|
||||
className={`search-container ${
|
||||
isFocused || inputValue ? "active" : ""
|
||||
}`}
|
||||
className={`search-container ${isFocused || inputValue ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="icon-container">
|
||||
<SearchIcon />
|
||||
@@ -48,7 +71,7 @@ const Search: React.FC<SearchProps> = ({
|
||||
<input
|
||||
type="text"
|
||||
className="search-input"
|
||||
value={inputValue}
|
||||
value={inputValue ?? ""}
|
||||
placeholder={placeholder}
|
||||
onChange={handleInputChange}
|
||||
onFocus={handleFocus}
|
||||
@@ -68,4 +91,4 @@ const Search: React.FC<SearchProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
export default Search;
|
||||
@@ -57,6 +57,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
const { zoneStore } = useSceneContext();
|
||||
const { zones, setZoneName } = zoneStore();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
useSelectedZoneStore.getState().setSelectedZone({
|
||||
zoneName: "",
|
||||
@@ -121,6 +122,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
}
|
||||
|
||||
function handleAssetClick(asset: Asset) {
|
||||
|
||||
setZoneAssetId(asset);
|
||||
}
|
||||
|
||||
@@ -157,8 +159,9 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
modelUuid: zoneAssetId.id,
|
||||
modelName: newName,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || ''
|
||||
|
||||
});
|
||||
// console.log("response: ", response);
|
||||
|
||||
setName(zoneAssetId.id, response.modelName);
|
||||
}
|
||||
@@ -255,9 +258,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={`list-item ${
|
||||
selectedZone.zoneUuid === item.id ? "active" : ""
|
||||
}`}
|
||||
className={`list-item ${selectedZone.zoneUuid === item.id ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="zone-header">
|
||||
<button className="value" id="zone-name">
|
||||
@@ -301,9 +303,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
{item.assets.map((asset) => (
|
||||
<li
|
||||
key={`asset-${asset.id}`}
|
||||
className={`list-container asset-item ${
|
||||
zoneAssetId?.id === asset.id ? "active" : ""
|
||||
}`}
|
||||
className={`list-container asset-item ${zoneAssetId?.id === asset.id ? "active" : ""
|
||||
}`}
|
||||
onClick={() => handleAssetClick(asset)}
|
||||
>
|
||||
<div className="list-item">
|
||||
|
||||
@@ -5,7 +5,9 @@ import { toggleTheme } from "../../../utils/theme";
|
||||
import useVersionHistoryVisibleStore, {
|
||||
useShortcutStore,
|
||||
} from "../../../store/builder/store";
|
||||
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
} from "../../../store/useModuleStore";
|
||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||
|
||||
interface MenuBarProps {
|
||||
@@ -21,11 +23,12 @@ interface MenuItem {
|
||||
}
|
||||
|
||||
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
|
||||
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 { setCreateNewVersion } = useVersionHistoryStore();
|
||||
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
@@ -49,7 +52,9 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
const theme = localStorage.getItem("theme") ?? "light";
|
||||
localStorage.clear();
|
||||
localStorage.setItem("theme", theme);
|
||||
navigate("/");
|
||||
};
|
||||
|
||||
@@ -61,7 +66,7 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
setCreateNewVersion(true);
|
||||
setVersionHistoryVisible(true);
|
||||
setSubModule("properties");
|
||||
setActiveModule('builder');
|
||||
setActiveModule("builder");
|
||||
}
|
||||
|
||||
const menus: Record<string, MenuItem[]> = {
|
||||
@@ -222,7 +227,7 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
||||
onClick={() => {
|
||||
setVersionHistoryVisible(true);
|
||||
setSubModule("properties");
|
||||
setActiveModule('builder');
|
||||
setActiveModule("builder");
|
||||
}}
|
||||
>
|
||||
<div className="menu-button">
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import type { CameraControls } from "@react-three/drei";
|
||||
|
||||
export const useCameraShortcuts = (controlsRef: React.RefObject<CameraControls>) => {
|
||||
const { camera } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (!controlsRef.current) return;
|
||||
|
||||
// get current distance from camera to target
|
||||
const target = new THREE.Vector3();
|
||||
controlsRef.current.getTarget(target);
|
||||
|
||||
const distance = camera.position.distanceTo(target);
|
||||
let pos: THREE.Vector3 | null = null;
|
||||
|
||||
switch (e.key) {
|
||||
case "1": // Front
|
||||
pos = new THREE.Vector3(0, 0, distance).add(target);
|
||||
break;
|
||||
case "3": // Right
|
||||
pos = new THREE.Vector3(distance, 0, 0).add(target);
|
||||
break;
|
||||
case "7": // Top
|
||||
pos = new THREE.Vector3(0, distance, 0).add(target);
|
||||
break;
|
||||
case "9": // Back
|
||||
pos = new THREE.Vector3(0, 0, -distance).add(target);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos) {
|
||||
controlsRef.current.setLookAt(
|
||||
pos.x, pos.y, pos.z, // camera position
|
||||
target.x, target.y, target.z, // keep same target
|
||||
true // smooth transition
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [controlsRef, camera]);
|
||||
};
|
||||
14
app/src/modules/builder/Decal/decal.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import DecalCreator from './decalCreator/decalCreator'
|
||||
|
||||
function Decal() {
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<DecalCreator />
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Decal
|
||||
159
app/src/modules/builder/Decal/decalCreator/decalCreator.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import { MathUtils } from 'three';
|
||||
import { useEffect } from 'react';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useSocketStore } from '../../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import useModuleStore from '../../../../store/useModuleStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useVersionContext } from '../../version/versionContext';
|
||||
|
||||
import { getUserData } from '../../../../functions/getUserData';
|
||||
|
||||
import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
|
||||
function DecalCreator() {
|
||||
const { wallStore, floorStore } = useSceneContext();
|
||||
const { addDecal: addDecalOnWall, getWallById } = wallStore();
|
||||
const { addDecal: addDecalOnFloor, getFloorById } = floorStore();
|
||||
const { droppedDecal, setDroppedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { socket } = useSocketStore();
|
||||
const { controls, gl, pointer, camera, raycaster, scene } = useThree();
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
if (droppedDecal) {
|
||||
setDroppedDecal(null);
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
const wallIntersect = intersects.find(i => i.object.userData && i.object.userData.wallUuid);
|
||||
const floorIntersect = intersects.find(i => i.object.userData && i.object.userData.floorUuid);
|
||||
|
||||
if (wallIntersect) {
|
||||
const wall = getWallById(wallIntersect.object.userData.wallUuid);
|
||||
if (!wall) return;
|
||||
|
||||
const point = wallIntersect.object.worldToLocal(wallIntersect.point.clone());
|
||||
|
||||
const decal: Decal = {
|
||||
decalUuid: MathUtils.generateUUID(),
|
||||
decalName: droppedDecal.decalName,
|
||||
decalId: droppedDecal.decalId,
|
||||
decalType: {
|
||||
type: 'Wall',
|
||||
wallUuid: wallIntersect.object.userData.wallUuid,
|
||||
},
|
||||
decalPosition: [point.x, point.y, (wall.wallThickness / 2 + 0.001) * (wallIntersect.normal?.z || 1)],
|
||||
decalRotation: 0,
|
||||
decalOpacity: 1,
|
||||
decalScale: 0.5,
|
||||
}
|
||||
|
||||
addDecalOnWall(wallIntersect.object.userData.wallUuid, decal);
|
||||
|
||||
setTimeout(() => {
|
||||
const updatedWall = getWallById(wallIntersect.object.userData.wallUuid);
|
||||
if (updatedWall) {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
} else if (floorIntersect) {
|
||||
const floor = getFloorById(floorIntersect.object.userData.floorUuid);
|
||||
if (!floor) return;
|
||||
|
||||
const point = floorIntersect.object.worldToLocal(floorIntersect.point.clone());
|
||||
|
||||
const decal: Decal = {
|
||||
decalUuid: MathUtils.generateUUID(),
|
||||
decalName: droppedDecal.decalName,
|
||||
decalId: droppedDecal.decalId,
|
||||
decalType: {
|
||||
type: 'Floor',
|
||||
floorUuid: floorIntersect.object.userData.floorUuid,
|
||||
},
|
||||
decalPosition: [point.x, point.y, -0.001],
|
||||
decalRotation: 0,
|
||||
decalOpacity: 1,
|
||||
decalScale: 0.5,
|
||||
}
|
||||
|
||||
addDecalOnFloor(floorIntersect.object.userData.floorUuid, decal);
|
||||
|
||||
setTimeout(() => {
|
||||
const updatedFloor = getFloorById(floorIntersect.object.userData.floorUuid);
|
||||
if (projectId && updatedFloor) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onDragOver = (event: any) => {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
if (activeModule === "builder") {
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
canvasElement.addEventListener("dragover", onDragOver);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
canvasElement.removeEventListener("dragover", onDragOver);
|
||||
};
|
||||
}, [droppedDecal, camera, activeModule, controls]);
|
||||
|
||||
return (
|
||||
<>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DecalCreator
|
||||
@@ -1,50 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import { Decal } from '@react-three/drei'
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { useToggleView } from '../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
|
||||
import defaultMaterial from '../../../assets/textures/floor/wall-tex.png';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
|
||||
function DecalInstance({ visible = true, decal, zPosition = decal.decalPosition[2] }: { visible?: boolean, decal: Decal, zPosition?: number }) {
|
||||
const { setSelectedWall, setSelectedFloor, selectedDecal, setSelectedDecal } = useBuilderStore();
|
||||
const { togglView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const material = useLoader(THREE.TextureLoader, defaultMaterial);
|
||||
|
||||
return (
|
||||
<Decal
|
||||
// debug
|
||||
visible={visible}
|
||||
position={[decal.decalPosition[0], decal.decalPosition[1], zPosition]}
|
||||
rotation={[0, 0, decal.decalRotation]}
|
||||
scale={[decal.decalScale, decal.decalScale, 0.01]}
|
||||
userData={decal}
|
||||
onClick={(e) => {
|
||||
if (visible && !togglView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
e.stopPropagation();
|
||||
setSelectedDecal(e.object);
|
||||
setSelectedWall(null);
|
||||
setSelectedFloor(null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) {
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
map={material}
|
||||
side={THREE.DoubleSide}
|
||||
polygonOffset
|
||||
polygonOffsetFactor={-1}
|
||||
/>
|
||||
</Decal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DecalInstance
|
||||
172
app/src/modules/builder/Decal/decalInstance/decalInstance.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
import * as THREE from 'three';
|
||||
import { Decal } from '@react-three/drei'
|
||||
import { useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import { retrieveImage, storeImage } from '../../../../utils/indexDB/idbUtils';
|
||||
|
||||
import defaultMaterial from '../../../../assets/image/fallback/fallback decal 1.png';
|
||||
import useModuleStore from '../../../../store/useModuleStore';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useDecalEventHandlers } from '../eventHandler/useDecalEventHandlers';
|
||||
|
||||
function DecalInstance({ parent, visible = true, decal, zPosition = decal.decalPosition[2] }: { parent: Wall | Floor; visible?: boolean, decal: Decal, zPosition?: number }) {
|
||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
const { selectedDecal, deletableDecal, setSelectedDecal, setDeletableDecal } = useBuilderStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const decalRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDecal?.decalData.decalUuid === decal.decalUuid && !selectedDecal.decalMesh) {
|
||||
setSelectedDecal({ decalData: selectedDecal.decalData, decalMesh: decalRef.current });
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [selectedDecal])
|
||||
|
||||
const { handlePointerMissed, handlePointerLeave, handleClick, handlePointerDown, handlePointerEnter } = useDecalEventHandlers({ parent, decal, visible });
|
||||
|
||||
const [texture, setTexture] = useState<THREE.Texture | null>(null);
|
||||
|
||||
const logDecalStatus = (decalId: string, status: string) => {
|
||||
// console.log(decalId, status);
|
||||
}
|
||||
|
||||
const loadDefaultTexture = () => {
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
textureLoader.load(
|
||||
defaultMaterial,
|
||||
(fallbackTex) => {
|
||||
fallbackTex.name = "default-decal";
|
||||
setTexture(fallbackTex);
|
||||
logDecalStatus(decal.decalId, 'default-loaded');
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
console.error("Error loading default decal texture:", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const loadDecalTexture = async (decalId: string) => {
|
||||
|
||||
try {
|
||||
const cachedTexture = THREE.Cache.get(decalId);
|
||||
if (cachedTexture) {
|
||||
setTexture(cachedTexture);
|
||||
logDecalStatus(decalId, 'cache-loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
const indexedDBTexture = await retrieveImage(decalId);
|
||||
if (indexedDBTexture) {
|
||||
const blobUrl = URL.createObjectURL(indexedDBTexture);
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
textureLoader.load(
|
||||
blobUrl,
|
||||
(tex) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
tex.name = decalId;
|
||||
THREE.Cache.add(decalId, tex);
|
||||
setTexture(tex);
|
||||
logDecalStatus(decalId, 'indexedDB-loaded');
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
console.error(`Error loading texture from IndexedDB:`, error);
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
loadFromBackend(decalId);
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
loadFromBackend(decalId);
|
||||
} catch (error) {
|
||||
console.error("Error loading decal texture:", error);
|
||||
loadDefaultTexture();
|
||||
}
|
||||
};
|
||||
|
||||
const loadFromBackend = (decalId: string) => {
|
||||
|
||||
const textureUrl = `${url_Backend_dwinzo}/api/v1/DecalImage/${decalId}`;
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
textureLoader.load(
|
||||
textureUrl,
|
||||
async (tex) => {
|
||||
tex.name = decalId;
|
||||
THREE.Cache.add(decalId, tex);
|
||||
setTexture(tex);
|
||||
logDecalStatus(decalId, 'backend-loaded');
|
||||
|
||||
try {
|
||||
const response = await fetch(textureUrl);
|
||||
const blob = await response.blob();
|
||||
await storeImage(decalId, blob);
|
||||
} catch (error) {
|
||||
console.error("Error storing texture in IndexedDB:", error);
|
||||
}
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
echo.error(`Error loading texture from backend: ${decal.decalName}`);
|
||||
loadDefaultTexture();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (decal.decalId) {
|
||||
loadDecalTexture(decal.decalId);
|
||||
} else {
|
||||
loadDefaultTexture();
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [decal.decalId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView && activeModule === 'builder') {
|
||||
if (toolMode !== 'cursor') {
|
||||
if (selectedDecal) setSelectedDecal(null);
|
||||
}
|
||||
if (toolMode !== '3D-Delete') {
|
||||
if (deletableDecal) setDeletableDecal(null);
|
||||
}
|
||||
} else {
|
||||
if (selectedDecal) setSelectedDecal(null);
|
||||
if (deletableDecal) setDeletableDecal(null);
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [toggleView, toolMode, activeModule, selectedDecal, deletableDecal]);
|
||||
|
||||
return (
|
||||
<Decal
|
||||
// debug
|
||||
visible={visible}
|
||||
ref={decalRef}
|
||||
position={[decal.decalPosition[0], decal.decalPosition[1], zPosition]}
|
||||
rotation={[0, 0, decal.decalRotation * (Math.PI / 180)]}
|
||||
scale={[(decal.decalType.type === 'Floor' || zPosition < 0) ? -decal.decalScale : decal.decalScale, decal.decalScale, 0.01]}
|
||||
userData={decal}
|
||||
onPointerDown={(e) => { if (e.button === 0) handlePointerDown(e) }}
|
||||
onClick={(e) => { handleClick(e) }}
|
||||
onPointerEnter={(e) => { handlePointerEnter(e) }}
|
||||
onPointerLeave={(e) => { handlePointerLeave(e) }}
|
||||
onPointerMissed={() => handlePointerMissed()}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
map={texture}
|
||||
side={THREE.DoubleSide}
|
||||
polygonOffset
|
||||
polygonOffsetFactor={-1}
|
||||
transparent
|
||||
opacity={decal.decalOpacity}
|
||||
/>
|
||||
</Decal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DecalInstance
|
||||
@@ -0,0 +1,359 @@
|
||||
import * as THREE from 'three';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import useModuleStore from '../../../../store/useModuleStore';
|
||||
import { getUserData } from '../../../../functions/getUserData';
|
||||
import { useVersionContext } from '../../version/versionContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
|
||||
import { detectModifierKeys } from '../../../../utils/shortcutkeys/detectModifierKeys';
|
||||
import handleDecalPositionSnap from '../functions/handleDecalPositionSnap';
|
||||
|
||||
import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
|
||||
export function useDecalEventHandlers({
|
||||
parent,
|
||||
decal,
|
||||
visible,
|
||||
}: {
|
||||
parent: Wall | Floor;
|
||||
decal: Decal;
|
||||
visible: boolean;
|
||||
}) {
|
||||
const { wallStore, floorStore } = useSceneContext();
|
||||
const { removeDecal: removeDecalInWall, updateDecalPosition: updateDecalPositionInWall, getWallById, addDecal: addDecalToWall } = wallStore();
|
||||
const { removeDecal: removeDecalInFloor, updateDecalPosition: updateDecalPositionInFloor, getFloorById, addDecal: addDecalToFloor } = floorStore();
|
||||
const { setSelectedWall, setSelectedFloor, setSelectedDecal, setDeletableDecal, deletableDecal, selectedDecal, setDecalDragState, decalDragState } = useBuilderStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { socket } = useSocketStore();
|
||||
const [keyEvent, setKeyEvent] = useState<"Ctrl" | "">("");
|
||||
const { raycaster, pointer, camera, scene, gl, controls } = useThree();
|
||||
|
||||
useFrame(() => {
|
||||
if (activeModule !== 'builder' || toggleView || !decalDragState.isDragging || !selectedDecal || selectedDecal.decalData.decalUuid !== decal.decalUuid) return;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
|
||||
const wallIntersect = intersects.find(i => i.object.userData?.wallUuid);
|
||||
const floorIntersect = intersects.find(i => i.object.userData?.floorUuid);
|
||||
|
||||
let offset = decalDragState.dragOffset || new THREE.Vector3(0, 0, 0);
|
||||
|
||||
if (wallIntersect) {
|
||||
const wallUuid = wallIntersect.object.userData.wallUuid;
|
||||
const point = wallIntersect.object.worldToLocal(wallIntersect.point.clone());
|
||||
|
||||
let finalPos;
|
||||
|
||||
if (keyEvent === "Ctrl") {
|
||||
finalPos = handleDecalPositionSnap(point, offset, parent, decal, 0.05)
|
||||
} else {
|
||||
finalPos = point
|
||||
}
|
||||
|
||||
if ("wallUuid" in parent && parent.wallUuid === wallUuid && decal.decalType.type === 'Wall') {
|
||||
updateDecalPositionInWall(decal.decalUuid, [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]]);
|
||||
} else if (decal.decalType.type === 'Wall' && wallUuid) {
|
||||
deleteDecal(decal.decalUuid, parent);
|
||||
|
||||
const addedDecal = addDecalToWall(wallUuid, {
|
||||
...decal,
|
||||
decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]],
|
||||
decalType: { type: 'Wall', wallUuid: wallUuid }
|
||||
});
|
||||
|
||||
if (addedDecal) {
|
||||
setSelectedDecal({ decalMesh: null, decalData: addedDecal })
|
||||
}
|
||||
} else if (decal.decalType.type === 'Floor' && wallUuid) {
|
||||
deleteDecal(decal.decalUuid, parent);
|
||||
const wall = getWallById(wallUuid);
|
||||
if (!wall) return;
|
||||
|
||||
const addedDecal = addDecalToWall(wallUuid, {
|
||||
...decal,
|
||||
decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, wall.wallThickness / 2 + 0.001],
|
||||
decalType: { type: 'Wall', wallUuid: wallUuid }
|
||||
});
|
||||
|
||||
if (addedDecal) {
|
||||
setSelectedDecal({ decalMesh: null, decalData: addedDecal })
|
||||
}
|
||||
}
|
||||
} else if (floorIntersect) {
|
||||
const floorUuid = floorIntersect.object.userData.floorUuid;
|
||||
const point = floorIntersect.object.worldToLocal(floorIntersect.point.clone());
|
||||
|
||||
let finalPos;
|
||||
|
||||
if (keyEvent === "Ctrl") {
|
||||
finalPos = handleDecalPositionSnap(point, offset, parent, decal, 0.25)
|
||||
} else {
|
||||
finalPos = point
|
||||
}
|
||||
|
||||
if ("floorUuid" in parent && parent.floorUuid === floorUuid && decal.decalType.type === 'Floor') {
|
||||
updateDecalPositionInFloor(decal.decalUuid, [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]]);
|
||||
} else if (decal.decalType.type === 'Floor' && floorUuid) {
|
||||
deleteDecal(decal.decalUuid, parent);
|
||||
|
||||
const addedDecal = addDecalToFloor(floorUuid, {
|
||||
...decal,
|
||||
decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, decal.decalPosition[2]],
|
||||
decalType: { type: 'Floor', floorUuid: floorUuid }
|
||||
});
|
||||
|
||||
if (addedDecal) {
|
||||
setSelectedDecal({ decalMesh: null, decalData: addedDecal })
|
||||
}
|
||||
} else if (decal.decalType.type === 'Wall' && floorUuid) {
|
||||
deleteDecal(decal.decalUuid, parent);
|
||||
const floor = getFloorById(floorUuid);
|
||||
if (!floor) return;
|
||||
|
||||
const addedDecal = addDecalToFloor(floorUuid, {
|
||||
...decal,
|
||||
decalPosition: [finalPos.x + offset.x, finalPos.y + offset.y, -0.001],
|
||||
decalType: { type: 'Floor', floorUuid: floorUuid }
|
||||
});
|
||||
|
||||
if (addedDecal) {
|
||||
setSelectedDecal({ decalMesh: null, decalData: addedDecal })
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const handlePointerUp = () => {
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
if (decalDragState.isDragging) {
|
||||
setDecalDragState(false, null, null);
|
||||
|
||||
if ('wallUuid' in parent) {
|
||||
setTimeout(() => {
|
||||
const updatedWall = getWallById(parent.wallUuid);
|
||||
if (updatedWall) {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
} else if ('floorUuid' in parent) {
|
||||
setTimeout(() => {
|
||||
const updatedFloor = parent;
|
||||
|
||||
if (projectId && updatedFloor) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteDecal = (decalUuid: string, parent: Wall | Floor) => {
|
||||
if ('wallUuid' in parent) {
|
||||
const updatedWall = removeDecalInWall(decalUuid);
|
||||
|
||||
if (projectId && updatedWall) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
} else if ('floorUuid' in parent) {
|
||||
const updatedFloor = removeDecalInFloor(decalUuid);
|
||||
|
||||
if (projectId && updatedFloor) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handlePointerDown = (e: ThreeEvent<MouseEvent>) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid && toolMode === 'cursor' && (selectedDecal && selectedDecal.decalData.decalUuid === decal.decalUuid)) {
|
||||
e.stopPropagation();
|
||||
setDecalDragState(true, decal.decalUuid, null);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = false;
|
||||
}
|
||||
setSelectedWall(null);
|
||||
setSelectedFloor(null);
|
||||
|
||||
const localIntersect = e.object.worldToLocal(e.point.clone());
|
||||
let dragOffset = new THREE.Vector3(decal.decalPosition[0] - localIntersect.x, decal.decalPosition[1] - localIntersect.y, 0);
|
||||
setDecalDragState(true, decal.decalUuid, dragOffset);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = (e: ThreeEvent<MouseEvent>) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
e.stopPropagation();
|
||||
if (toolMode === 'cursor') {
|
||||
setSelectedDecal({ decalMesh: e.object, decalData: decal });
|
||||
setSelectedWall(null);
|
||||
setSelectedFloor(null);
|
||||
} else if (toolMode === '3D-Delete') {
|
||||
deleteDecal(e.object.userData.decalUuid, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerEnter = (e: ThreeEvent<MouseEvent>) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
e.stopPropagation();
|
||||
if (toolMode === '3D-Delete') {
|
||||
setDeletableDecal(e.object);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerLeave = (e: ThreeEvent<MouseEvent>) => {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.decalUuid) {
|
||||
e.stopPropagation();
|
||||
if (toolMode === '3D-Delete' && deletableDecal && deletableDecal?.userData.decalUuid === e.object.userData.decalUuid) {
|
||||
setDeletableDecal(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerMissed = () => {
|
||||
if (selectedDecal && selectedDecal.decalMesh && selectedDecal.decalMesh.userData.decalUuid === decal.decalUuid) {
|
||||
setSelectedDecal(null);
|
||||
setKeyEvent("");
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyUp = (event: KeyboardEvent) => {
|
||||
const keyCombination = detectModifierKeys(event);
|
||||
|
||||
if (keyCombination === "") {
|
||||
setKeyEvent("");
|
||||
} else if (keyCombination === "Ctrl") {
|
||||
setKeyEvent(keyCombination);
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
const keyCombination = detectModifierKeys(event);
|
||||
if (keyCombination !== keyEvent) {
|
||||
if (keyCombination === "Ctrl") {
|
||||
setKeyEvent(keyCombination);
|
||||
} else {
|
||||
setKeyEvent("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
if (activeModule === 'builder' && !toggleView && selectedDecal && selectedDecal.decalData.decalUuid === decal.decalUuid) {
|
||||
canvasElement.addEventListener('pointerup', handlePointerUp);
|
||||
canvasElement?.addEventListener("keyup", onKeyUp);
|
||||
canvasElement.addEventListener("keydown", onKeyDown);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener('pointerup', handlePointerUp);
|
||||
canvasElement?.removeEventListener("keyup", onKeyUp);
|
||||
canvasElement.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
// eslint-disable-next-line
|
||||
}, [gl, activeModule, toggleView, selectedDecal, camera, controls, visible, parent, decal, decalDragState]);
|
||||
|
||||
return {
|
||||
handlePointerDown,
|
||||
handleClick,
|
||||
handlePointerEnter,
|
||||
handlePointerLeave,
|
||||
handlePointerMissed,
|
||||
deleteDecal
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
function snapToFixedPoint(
|
||||
position: [number, number, number],
|
||||
snapInterval: number = 0.1
|
||||
): [number, number, number] {
|
||||
return [
|
||||
Math.round(position[0] / snapInterval) * snapInterval,
|
||||
Math.round(position[1] / snapInterval) * snapInterval,
|
||||
Math.round(position[2] / snapInterval) * snapInterval,
|
||||
];
|
||||
}
|
||||
|
||||
function handleDecalPositionSnap(
|
||||
point: THREE.Vector3,
|
||||
offset: THREE.Vector3,
|
||||
parent: Wall | Floor,
|
||||
decal: Decal,
|
||||
snapInterval: number = 0.1
|
||||
): THREE.Vector3 {
|
||||
let rawPos: [number, number, number];
|
||||
|
||||
if ("wallUuid" in parent) {
|
||||
// snap relative to wall
|
||||
rawPos = [
|
||||
point.x + offset.x,
|
||||
point.y + offset.y,
|
||||
decal.decalPosition[2], // keep depth as-is
|
||||
];
|
||||
} else {
|
||||
// snap relative to floor
|
||||
rawPos = [
|
||||
point.x + offset.x,
|
||||
point.y + offset.y,
|
||||
decal.decalPosition[2],
|
||||
];
|
||||
}
|
||||
|
||||
const snapped = snapToFixedPoint(rawPos, snapInterval);
|
||||
return new THREE.Vector3(snapped[0], snapped[1], snapped[2]);
|
||||
}
|
||||
|
||||
export default handleDecalPositionSnap;
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const arc = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-aisle') return null;
|
||||
@@ -63,8 +69,8 @@ function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const arrow = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') return null;
|
||||
@@ -50,8 +56,8 @@ function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Instances, Instance } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const { arrowGeometry, arrowInstances } = useMemo(() => {
|
||||
const result = {
|
||||
@@ -68,8 +74,8 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const circle = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null;
|
||||
@@ -38,8 +44,8 @@ function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Instances, Instance } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const dashInstances = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dashed-aisle') return [];
|
||||
@@ -43,8 +49,8 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Instance, Instances } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const dotPositions = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'dotted-aisle') return [];
|
||||
@@ -27,8 +33,8 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,13 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const arrows = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') return null;
|
||||
@@ -85,8 +91,8 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as THREE from 'three';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../../types/world/worldConstants';
|
||||
import { useToolMode } from '../../../../../../store/builder/store';
|
||||
@@ -8,7 +8,14 @@ import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore
|
||||
function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
const aisleRef = useRef<THREE.Group>(null);
|
||||
const { toolMode } = useToolMode();
|
||||
const { setSelectedAisle, hoveredPoint } = useBuilderStore();
|
||||
const { setSelectedAisle, hoveredPoint, selectedAisle } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAisle?.aisleData.aisleUuid === aisle.aisleUuid && !selectedAisle.aisleMesh) {
|
||||
setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: aisleRef.current });
|
||||
}
|
||||
}, [selectedAisle])
|
||||
|
||||
const shape = useMemo(() => {
|
||||
if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') return null;
|
||||
|
||||
@@ -35,8 +42,8 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
}, [aisle]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (toolMode === 'move' && !hoveredPoint) {
|
||||
setSelectedAisle(aisleRef.current);
|
||||
if ((toolMode === 'move' || toolMode === 'cursor') && !hoveredPoint) {
|
||||
setSelectedAisle({ aisleMesh: aisleRef.current, aisleData: aisle });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import ReferenceAisle from './referenceAisle';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import { getUserData } from '../../../../functions/getUserData';
|
||||
|
||||
// import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||
import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||
|
||||
function AisleCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -93,431 +93,70 @@ function AisleCreator() {
|
||||
}
|
||||
}
|
||||
|
||||
if (aisleType === 'solid-aisle') {
|
||||
const aisleConfigs: Record<string, (color: string) => any> = {
|
||||
"solid-aisle": (color) => ({ aisleType: "solid-aisle", aisleColor: color, aisleWidth }),
|
||||
"dashed-aisle": (color) => ({ aisleType: "dashed-aisle", aisleColor: color, aisleWidth, dashLength, gapLength }),
|
||||
"dotted-aisle": (color) => ({ aisleType: "dotted-aisle", aisleColor: color, dotRadius, gapLength }),
|
||||
"arrow-aisle": (color) => ({ aisleType: "arrow-aisle", aisleColor: color, aisleWidth }),
|
||||
"arrows-aisle": (color) => ({ aisleType: "arrows-aisle", aisleColor: color, aisleWidth, aisleLength, gapLength }),
|
||||
"arc-aisle": (color) => ({ aisleType: "arc-aisle", aisleColor: color, aisleWidth, isFlipped }),
|
||||
"circle-aisle": (color) => ({ aisleType: "circle-aisle", aisleColor: color, aisleWidth }),
|
||||
"junction-aisle": (color) => ({ aisleType: "junction-aisle", aisleColor: color, aisleWidth, isFlipped })
|
||||
};
|
||||
|
||||
if (!aisleType || !(aisleType in aisleConfigs)) return;
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: aisleConfigs[aisleType](aisleColor)
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: "Draw",
|
||||
actions: [{
|
||||
actionType: "Line-Create",
|
||||
point: { type: "Aisle", lineData: aisle, timeStamp: new Date().toISOString() }
|
||||
}]
|
||||
});
|
||||
|
||||
addAilseToBackend(aisle);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
};
|
||||
|
||||
const addAilseToBackend = (aisle: Aisle) => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'solid-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
// SOCKET
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'dashed-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'dashed-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
dashLength: dashLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'dotted-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'dotted-aisle',
|
||||
aisleColor: aisleColor,
|
||||
dotRadius: dotRadius,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'arrow-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'arrow-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'arrows-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'arrows-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
aisleLength: aisleLength,
|
||||
gapLength: gapLength
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'arc-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'arc-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
isFlipped: isFlipped
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'circle-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'circle-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
} else if (aisleType === 'junction-aisle') {
|
||||
|
||||
if (tempPoints.length === 0) {
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
const aisle: Aisle = {
|
||||
aisleUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [tempPoints[0], newPoint],
|
||||
type: {
|
||||
aisleType: 'junction-aisle',
|
||||
aisleColor: aisleColor,
|
||||
aisleWidth: aisleWidth,
|
||||
isFlipped: isFlipped
|
||||
}
|
||||
};
|
||||
|
||||
addAisle(aisle);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
{
|
||||
actionType: 'Line-Create',
|
||||
point: {
|
||||
type: 'Aisle',
|
||||
lineData: aisle,
|
||||
timeStamp: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
})
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
socket.emit("v1:model-aisle:add", {
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
userId,
|
||||
organization,
|
||||
aisleUuid: aisle.aisleUuid,
|
||||
points: aisle.points,
|
||||
type: aisle.type
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const onContext = (event: any) => {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as THREE from "three"
|
||||
import { useEffect } from 'react'
|
||||
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||
import { useLoadingProgress, useRenameModeStore, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import { FloorItems, RefMesh } from "../../../types/world/worldTypes";
|
||||
@@ -15,6 +15,7 @@ import { useLeftData, useTopData } from "../../../store/visualization/useZone3DW
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../scene/sceneContext";
|
||||
import { useVersionContext } from "../version/versionContext";
|
||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||
|
||||
const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url));
|
||||
|
||||
@@ -28,7 +29,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { setAssets, addAsset, clearAssets } = assetStore();
|
||||
const { addEvent, clearEvents } = eventStore();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { setSelectedFloorAsset } = useBuilderStore();
|
||||
const { selectedItem, setSelectedItem } = useSelectedItem();
|
||||
const { projectId } = useParams();
|
||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||
@@ -363,6 +364,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
setLeft(relativeX);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
setIsRenameMode(false);
|
||||
}
|
||||
@@ -376,7 +378,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
if ((controls as CameraControls)) {
|
||||
const target = (controls as CameraControls).getTarget(new THREE.Vector3());
|
||||
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
||||
setSelectedFloorItem(null);
|
||||
setSelectedFloorAsset(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
||||
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
|
||||
async function addAssetModel(
|
||||
scene: THREE.Scene,
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
socket: Socket<any>,
|
||||
socket: Socket<any> | null,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
@@ -106,7 +106,7 @@ async function handleModelLoad(
|
||||
selectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
socket: Socket<any>,
|
||||
socket: Socket<any> | null,
|
||||
versionId: string,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
@@ -140,22 +140,6 @@ async function handleModelLoad(
|
||||
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,
|
||||
@@ -449,14 +433,34 @@ async function handleModelLoad(
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
socketId: socket?.id || '',
|
||||
eventData: eventData,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
setAssetsApi({
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
assetId: newFloorItem.assetId,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
eventData: eventData,
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
});
|
||||
|
||||
} else {
|
||||
// SOCKET
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
}
|
||||
|
||||
const asset: Asset = {
|
||||
modelUuid: completeData.modelUuid,
|
||||
@@ -482,13 +486,32 @@ async function handleModelLoad(
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
socketId: socket?.id || '',
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
setAssetsApi({
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
assetId: newFloorItem.assetId,
|
||||
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
});
|
||||
|
||||
} else {
|
||||
// SOCKET
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
}
|
||||
|
||||
const asset = {
|
||||
modelUuid: data.modelUuid,
|
||||
|
||||
@@ -3,9 +3,8 @@ import { CameraControls } from '@react-three/drei';
|
||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
import { useActiveTool, useDeletableFloorItem, useSelectedFloorItem, useToggleView, useZoneAssetId } from '../../../../../../store/builder/store';
|
||||
import { useActiveTool, useResourceManagementId, useToggleView, useZoneAssetId, useSocketStore } from '../../../../../../store/builder/store';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../../store/useModuleStore';
|
||||
import { useSocketStore } from '../../../../../../store/builder/store';
|
||||
import { useSceneContext } from '../../../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../../../../simulation/products/productContext';
|
||||
import { useVersionContext } from '../../../../version/versionContext';
|
||||
@@ -13,9 +12,10 @@ import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../../../../functions/getUserData';
|
||||
import { useLeftData, useTopData } from '../../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../../store/simulation/useSimulationStore';
|
||||
import { upsertProductOrEventApi } from '../../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore';
|
||||
|
||||
// import { deleteFloorItem } from '../../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
|
||||
import { upsertProductOrEventApi } from '../../../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
import { deleteFloorItem } from '../../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
|
||||
|
||||
export function useModelEventHandlers({
|
||||
boundingBox,
|
||||
@@ -34,13 +34,13 @@ export function useModelEventHandlers({
|
||||
const { socket } = useSocketStore();
|
||||
const { eventStore, productStore, assetStore, undoRedo3DStore } = useSceneContext();
|
||||
const { push3D } = undoRedo3DStore();
|
||||
const { getAssetById, removeAsset } = assetStore();
|
||||
const { removeAsset } = assetStore();
|
||||
const { zoneAssetId, setZoneAssetId } = useZoneAssetId();
|
||||
const { resourceManagementId, setResourceManagementId } = useResourceManagementId();
|
||||
const { removeEvent, getEventByModelUuid } = eventStore();
|
||||
const { getIsEventInProduct, addPoint, deleteEvent } = productStore();
|
||||
const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { deletableFloorAsset, setDeletableFloorAsset, selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
@@ -74,19 +74,28 @@ export function useModelEventHandlers({
|
||||
if (zoneAssetId.id === asset.modelUuid) {
|
||||
handleDblClick(asset);
|
||||
}
|
||||
|
||||
}, [zoneAssetId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedFloorItem) {
|
||||
if (!resourceManagementId) return
|
||||
if (resourceManagementId === asset.modelUuid) {
|
||||
|
||||
|
||||
handleDblClick(asset);
|
||||
}
|
||||
|
||||
}, [resourceManagementId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedFloorAsset) {
|
||||
setZoneAssetId(null);
|
||||
}
|
||||
}, [selectedFloorItem])
|
||||
}, [selectedFloorAsset])
|
||||
|
||||
const handleDblClick = (asset: Asset) => {
|
||||
if (asset && activeTool === "cursor" && boundingBox && groupRef.current && activeModule === 'builder') {
|
||||
|
||||
if (asset && activeTool === "cursor" && boundingBox && groupRef.current && (activeModule === 'builder' || (activeModule === 'simulation' && resourceManagementId))) {
|
||||
const frontView = false;
|
||||
|
||||
if (frontView) {
|
||||
const size = boundingBox.getSize(new THREE.Vector3());
|
||||
const center = boundingBox.getCenter(new THREE.Vector3());
|
||||
@@ -107,6 +116,7 @@ export function useModelEventHandlers({
|
||||
paddingBottom: 5,
|
||||
paddingRight: 5,
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
const collisionPos = new THREE.Vector3();
|
||||
@@ -126,32 +136,37 @@ export function useModelEventHandlers({
|
||||
(controls as CameraControls).setLookAt(newCameraPos.x, newCameraPos.y, newCameraPos.z, collisionPos.x, 0, collisionPos.z, true);
|
||||
}
|
||||
|
||||
setSelectedFloorItem(groupRef.current);
|
||||
setSelectedFloorAsset(groupRef.current);
|
||||
setResourceManagementId("");
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = async (evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||
if (leftDrag.current || toggleView) return;
|
||||
if (activeTool === 'delete' && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
if (activeTool === 'delete' && deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
|
||||
|
||||
//REST
|
||||
if (!socket?.connected) {
|
||||
|
||||
// const response = await deleteFloorItem(organization, asset.modelUuid, asset.modelName);
|
||||
// REST
|
||||
|
||||
//SOCKET
|
||||
deleteFloorItem(organization, asset.modelUuid, asset.modelName);
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
modelName: asset.modelName,
|
||||
socketId: socket.id,
|
||||
userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId
|
||||
} else {
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
modelName: asset.modelName,
|
||||
socketId: socket.id,
|
||||
userId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId
|
||||
}
|
||||
|
||||
socket.emit('v1:model-asset:delete', data)
|
||||
}
|
||||
|
||||
const response = socket.emit('v1:model-asset:delete', data)
|
||||
|
||||
removeEvent(asset.modelUuid);
|
||||
const updatedEvents = deleteEvent(asset.modelUuid);
|
||||
|
||||
@@ -164,27 +179,24 @@ export function useModelEventHandlers({
|
||||
);
|
||||
})
|
||||
|
||||
if (response) {
|
||||
removeAsset(asset.modelUuid);
|
||||
|
||||
removeAsset(asset.modelUuid);
|
||||
|
||||
push3D({
|
||||
type: 'Scene',
|
||||
actions: [
|
||||
{
|
||||
module: "builder",
|
||||
actionType: "Asset-Delete",
|
||||
asset: {
|
||||
type: "Asset",
|
||||
assetData: asset,
|
||||
timeStap: new Date().toISOString()
|
||||
}
|
||||
push3D({
|
||||
type: 'Scene',
|
||||
actions: [
|
||||
{
|
||||
module: "builder",
|
||||
actionType: "Asset-Delete",
|
||||
asset: {
|
||||
type: "Asset",
|
||||
assetData: asset,
|
||||
timeStap: new Date().toISOString()
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
echo.success("Model Removed!");
|
||||
}
|
||||
echo.success("Model Removed!");
|
||||
|
||||
} else if (activeModule === 'simulation' && subModule === "simulations" && activeTool === 'pen') {
|
||||
if (asset.eventData && asset.eventData.type === 'Conveyor') {
|
||||
@@ -224,19 +236,19 @@ export function useModelEventHandlers({
|
||||
|
||||
const handlePointerOver = useCallback((asset: Asset) => {
|
||||
if (activeTool === "delete" && activeModule === 'builder') {
|
||||
if (deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
if (deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
|
||||
return;
|
||||
} else {
|
||||
setDeletableFloorItem(groupRef.current);
|
||||
setDeletableFloorAsset(groupRef.current);
|
||||
}
|
||||
}
|
||||
}, [activeTool, activeModule, deletableFloorItem]);
|
||||
}, [activeTool, activeModule, deletableFloorAsset]);
|
||||
|
||||
const handlePointerOut = useCallback((evt: ThreeEvent<MouseEvent>, asset: Asset) => {
|
||||
if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorItem && deletableFloorItem.uuid === asset.modelUuid) {
|
||||
setDeletableFloorItem(null);
|
||||
if (evt.intersections.length === 0 && activeTool === "delete" && deletableFloorAsset && deletableFloorAsset.uuid === asset.modelUuid) {
|
||||
setDeletableFloorAsset(null);
|
||||
}
|
||||
}, [activeTool, deletableFloorItem]);
|
||||
}, [activeTool, deletableFloorAsset]);
|
||||
|
||||
const handleContextMenu = (asset: Asset, evt: ThreeEvent<MouseEvent>) => {
|
||||
if (rightDrag.current || toggleView) return;
|
||||
|
||||
@@ -2,8 +2,9 @@ import * as THREE from 'three';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||
import useModuleStore from '../../../../../store/useModuleStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import { SkeletonUtils } from 'three-stdlib';
|
||||
@@ -19,15 +20,13 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { resetAnimation } = assetStore();
|
||||
const { setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { resetAnimation, selectedAssets } = assetStore();
|
||||
const { setDeletableFloorAsset, selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
|
||||
const [gltfScene, setGltfScene] = useState<GLTF["scene"] | null>(null);
|
||||
const [boundingBox, setBoundingBox] = useState<THREE.Box3 | null>(null);
|
||||
const [isSelected, setIsSelected] = useState(false);
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const [fieldData, setFieldData] = useState<any>();
|
||||
const { selectedAssets } = useSelectedAssets();
|
||||
|
||||
useEffect(() => {
|
||||
if (!fieldData && asset.eventData) {
|
||||
@@ -53,17 +52,17 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
}, [asset.modelUuid, fieldData])
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
if (selectedFloorItem === null || selectedFloorItem.userData.modelUuid !== asset.modelUuid) {
|
||||
setDeletableFloorAsset(null);
|
||||
if (selectedFloorAsset === null || selectedFloorAsset.userData.modelUuid !== asset.modelUuid) {
|
||||
resetAnimation(asset.modelUuid);
|
||||
}
|
||||
}, [activeModule, toolMode, selectedFloorItem])
|
||||
}, [activeModule, toolMode, selectedFloorAsset])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedFloorItem && selectedFloorItem.userData.modelUuid === asset.modelUuid) {
|
||||
setSelectedFloorItem(groupRef.current);
|
||||
if (selectedFloorAsset && selectedFloorAsset.userData.modelUuid === asset.modelUuid) {
|
||||
setSelectedFloorAsset(groupRef.current);
|
||||
}
|
||||
}, [isRendered, selectedFloorItem])
|
||||
}, [isRendered, selectedFloorAsset])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedAssets.length > 0) {
|
||||
@@ -88,6 +87,10 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
}
|
||||
}, [gltfScene]);
|
||||
|
||||
const logModelStatus = (modelId: string, status: string) => {
|
||||
// console.log(modelId, status);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Calculate Bounding Box
|
||||
const calculateBoundingBox = (scene: THREE.Object3D) => {
|
||||
@@ -103,6 +106,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
clone.animations = cachedModel.animations || [];
|
||||
setGltfScene(clone);
|
||||
calculateBoundingBox(clone);
|
||||
logModelStatus(assetId, 'cache-loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,6 +122,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
THREE.Cache.add(assetId, gltf);
|
||||
setGltfScene(gltf.scene.clone());
|
||||
calculateBoundingBox(gltf.scene);
|
||||
logModelStatus(assetId, 'indexedDB-loaded');
|
||||
},
|
||||
undefined,
|
||||
(error) => {
|
||||
@@ -140,6 +145,7 @@ function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendere
|
||||
THREE.Cache.add(assetId, gltf);
|
||||
setGltfScene(gltf.scene.clone());
|
||||
calculateBoundingBox(gltf.scene);
|
||||
logModelStatus(assetId, 'backend-loaded');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
|
||||
@@ -2,9 +2,10 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
import { Group, Vector3 } from "three";
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { useLimitDistance, useRenderDistance, useSelectedFloorItem, useToggleView } from '../../../../store/builder/store';
|
||||
import { useLimitDistance, useRenderDistance } from '../../../../store/builder/store';
|
||||
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
import Model from './model/model';
|
||||
import { GLTFLoader } from "three/examples/jsm/Addons";
|
||||
@@ -16,7 +17,7 @@ function Models({ loader }: { loader: GLTFLoader }) {
|
||||
const assetGroupRef = useRef<Group>(null);
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets } = assetStore();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
|
||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||
const { limitDistance } = useLimitDistance();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
@@ -49,10 +50,10 @@ function Models({ loader }: { loader: GLTFLoader }) {
|
||||
ref={assetGroupRef}
|
||||
onPointerMissed={(e) => {
|
||||
e.stopPropagation();
|
||||
if (selectedFloorItem) {
|
||||
if (selectedFloorAsset) {
|
||||
const target = (controls as CameraControls).getTarget(new Vector3());
|
||||
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
||||
setSelectedFloorItem(null);
|
||||
setSelectedFloorAsset(null);
|
||||
}
|
||||
if (selectedAsset) {
|
||||
clearSelectedAsset();
|
||||
|
||||
@@ -33,13 +33,14 @@ import AssetsGroup from "./asset/assetsGroup";
|
||||
import DxfFile from "./dfx/LoadBlueprint";
|
||||
import AislesGroup from "./aisle/aislesGroup";
|
||||
import WallGroup from "./wall/wallGroup";
|
||||
import WallAssetGroup from "./wallAsset/wallAssetGroup";
|
||||
import FloorGroup from "./floor/floorGroup";
|
||||
import ZoneGroup from "./zone/zoneGroup";
|
||||
import Decal from "./Decal/decal";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useBuilderStore } from "../../store/builder/useBuilderStore";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import WallAssetGroup from "./wallAsset/wallAssetGroup";
|
||||
|
||||
export default function Builder() {
|
||||
const state = useThree<Types.ThreeState>();
|
||||
@@ -106,6 +107,8 @@ export default function Builder() {
|
||||
</Geometry>
|
||||
</mesh>
|
||||
|
||||
<Decal />
|
||||
|
||||
<AislesGroup />
|
||||
|
||||
<FloorGroup />
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useVersionContext } from '../version/versionContext';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
|
||||
import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
|
||||
/**
|
||||
* DxfFile component handles the rendering and manipulation of DXf file data in a 3D scene.
|
||||
* It processes the DXF data to create points and lines representing walls and allows
|
||||
@@ -39,20 +41,25 @@ const DxfFile = () => {
|
||||
|
||||
if (dfxWallGenerate) {
|
||||
dfxWallGenerate.map((wall: Wall) => {
|
||||
const data = {
|
||||
wallData: wall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
addWall(wall);
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall);
|
||||
} else {
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: wall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
addWall(wall);
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [dfxWallGenerate]);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useMemo } from "react";
|
||||
import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace, NoColorSpace, } from "three";
|
||||
import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace, NoColorSpace, ExtrudeGeometry, Vector3, Euler, } from "three";
|
||||
import { useLoader } from "@react-three/fiber";
|
||||
import { Extrude } from "@react-three/drei";
|
||||
import useModuleStore from "../../../../../store/useModuleStore";
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
import { useToggleView } from "../../../../../store/builder/store";
|
||||
import * as Constants from "../../../../../types/world/worldConstants";
|
||||
|
||||
import DecalInstance from "../../../Decal/decalInstance/decalInstance";
|
||||
|
||||
import texturePath from "../../../../../assets/textures/floor/white.png";
|
||||
import texturePathDark from "../../../../../assets/textures/floor/black.png";
|
||||
import material1 from "../../../../../assets/textures/floor/factory wall texture.jpg";
|
||||
@@ -28,7 +29,7 @@ import material4MetalicMap from "../../../../../assets/textures/floor/tex3/metal
|
||||
import material4NormalMap from "../../../../../assets/textures/floor/tex3/metal_plate_nor_gl_1k.png";
|
||||
|
||||
function FloorInstance({ floor }: { floor: Floor }) {
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedFloor, setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||
const savedTheme = localStorage.getItem("theme");
|
||||
@@ -67,20 +68,26 @@ function FloorInstance({ floor }: { floor: Floor }) {
|
||||
},
|
||||
};
|
||||
|
||||
const shape = useMemo(() => {
|
||||
const shape = new Shape();
|
||||
const shapeData = useMemo(() => {
|
||||
const points = floor.points.map((p) => new Vector2(p.position[0], p.position[2]));
|
||||
if (points.length < 3) return null;
|
||||
shape.moveTo(points[0].x, points[0].y);
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
shape.lineTo(points[i].x, points[i].y);
|
||||
|
||||
const centroidX = points.reduce((sum, p) => sum + p.x, 0) / points.length;
|
||||
const centroidY = points.reduce((sum, p) => sum + p.y, 0) / points.length;
|
||||
|
||||
const relativePoints = points.map((p) => new Vector2(p.x - centroidX, p.y - centroidY));
|
||||
|
||||
const shape = new Shape();
|
||||
shape.moveTo(relativePoints[0].x, relativePoints[0].y);
|
||||
for (let i = 1; i < relativePoints.length; i++) {
|
||||
shape.lineTo(relativePoints[i].x, relativePoints[i].y);
|
||||
}
|
||||
return shape;
|
||||
|
||||
return { shape, center: [centroidX, centroidY] };
|
||||
}, [floor]);
|
||||
|
||||
const textureScale = Constants.floorConfig.textureScale;
|
||||
|
||||
// Helper function to handle texture maps and filter out null values
|
||||
function getMaterialMaps(material: any, defaultMap: any) {
|
||||
const materialMap = material.map || defaultMap;
|
||||
const normalMap = material.normalMap || null;
|
||||
@@ -90,26 +97,18 @@ function FloorInstance({ floor }: { floor: Floor }) {
|
||||
return [materialMap, normalMap, roughnessMap, metalnessMap].filter((texture): texture is string => texture !== null);
|
||||
}
|
||||
|
||||
// Default material map
|
||||
const defaultMaterialMap = materials["Default Material"].map;
|
||||
|
||||
// Get top and side material maps
|
||||
const topMaterial = materials[floor.topMaterial];
|
||||
const sideMaterial = materials[floor.sideMaterial];
|
||||
|
||||
// Get the filtered lists for top and side textures
|
||||
const topTexturesList = getMaterialMaps(topMaterial, defaultMaterialMap);
|
||||
const sideTexturesList = getMaterialMaps(sideMaterial, defaultMaterialMap);
|
||||
|
||||
// Use loader to load top and side textures
|
||||
const [topTexture, topNormalTexture, topRoughnessTexture, topMetalicTexture] = useLoader(TextureLoader, topTexturesList);
|
||||
|
||||
const [sideTexture, sideNormalTexture, sideRoughnessTexture, sideMetalicTexture] = useLoader(TextureLoader, sideTexturesList);
|
||||
|
||||
// Early exit if materials are missing
|
||||
if (!materials[floor.topMaterial] || !materials[floor.sideMaterial]) return null;
|
||||
|
||||
// Combine and pair textures with their corresponding material
|
||||
const textureMaterialMap = [
|
||||
{
|
||||
textures: [
|
||||
@@ -131,7 +130,6 @@ function FloorInstance({ floor }: { floor: Floor }) {
|
||||
},
|
||||
];
|
||||
|
||||
// Apply texture settings
|
||||
textureMaterialMap.forEach(({ textures, materialKey }) => {
|
||||
const tileScale = materials[materialKey]?.textureTileScale ?? [
|
||||
textureScale,
|
||||
@@ -143,23 +141,39 @@ function FloorInstance({ floor }: { floor: Floor }) {
|
||||
tex.wrapS = tex.wrapT = RepeatWrapping;
|
||||
tex.repeat.set(tileScale[0], tileScale[1]);
|
||||
tex.anisotropy = 16;
|
||||
// First texture is always the color map (use SRGB), others should be linear
|
||||
tex.colorSpace = idx < 1 ? SRGBColorSpace : NoColorSpace;
|
||||
});
|
||||
});
|
||||
|
||||
if (!shape) return null;
|
||||
const geometry = useMemo(() => {
|
||||
if (!shapeData) return null;
|
||||
return new ExtrudeGeometry(shapeData.shape, {
|
||||
depth: !floor.isBeveled ? floor.floorDepth : floor.floorDepth - 0.1,
|
||||
bevelEnabled: floor.isBeveled,
|
||||
bevelSegments: floor.bevelStrength,
|
||||
bevelOffset: -0.1,
|
||||
bevelSize: 0.1,
|
||||
bevelThickness: 0.1,
|
||||
});
|
||||
}, [shapeData, floor]);
|
||||
|
||||
if (!geometry) return null;
|
||||
|
||||
return (
|
||||
<mesh
|
||||
castShadow
|
||||
receiveShadow
|
||||
geometry={geometry}
|
||||
name={`Floor-${floor.floorUuid}`}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
position={[0, !floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2, 0,]}
|
||||
position={[
|
||||
shapeData?.center[0] ?? 0,
|
||||
!floor.isBeveled ? floor.floorDepth - 0.1 : floor.floorDepth - 0.2,
|
||||
shapeData?.center[1] ?? 0,
|
||||
]}
|
||||
userData={floor}
|
||||
onDoubleClick={(e) => {
|
||||
if (!togglView && activeModule === "builder") {
|
||||
if (!toggleView && activeModule === "builder") {
|
||||
if (e.object.userData.floorUuid) {
|
||||
e.stopPropagation();
|
||||
setSelectedFloor(e.object);
|
||||
@@ -173,41 +187,32 @@ function FloorInstance({ floor }: { floor: Floor }) {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Extrude
|
||||
name={`Floor-${floor.floorUuid}`}
|
||||
args={[shape,
|
||||
{
|
||||
depth: !floor.isBeveled ? floor.floorDepth : floor.floorDepth - 0.1,
|
||||
bevelEnabled: floor.isBeveled,
|
||||
bevelSegments: floor.bevelStrength,
|
||||
bevelOffset: -0.1,
|
||||
bevelSize: 0.1,
|
||||
bevelThickness: 0.1,
|
||||
},
|
||||
]}
|
||||
userData={floor}
|
||||
>
|
||||
<meshPhysicalMaterial
|
||||
attach="material-0"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={topTexture}
|
||||
roughnessMap={topRoughnessTexture}
|
||||
metalnessMap={topMetalicTexture}
|
||||
normalMap={topNormalTexture}
|
||||
roughness={1.5}
|
||||
metalness={1.0}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
<meshStandardMaterial
|
||||
attach="material-1"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={sideTexture?.clone()}
|
||||
roughnessMap={sideRoughnessTexture?.clone()}
|
||||
metalnessMap={sideMetalicTexture?.clone()}
|
||||
normalMap={sideNormalTexture?.clone()}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
<meshPhysicalMaterial
|
||||
attach="material-0"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={topTexture}
|
||||
roughnessMap={topRoughnessTexture}
|
||||
metalnessMap={topMetalicTexture}
|
||||
normalMap={topNormalTexture}
|
||||
roughness={1.5}
|
||||
metalness={1.0}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
<meshStandardMaterial
|
||||
attach="material-1"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={sideTexture?.clone()}
|
||||
roughnessMap={sideRoughnessTexture?.clone()}
|
||||
metalnessMap={sideMetalicTexture?.clone()}
|
||||
normalMap={sideNormalTexture?.clone()}
|
||||
roughness={1.5}
|
||||
metalness={1.0}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
|
||||
{floor.decals.map((decal) => (
|
||||
<DecalInstance parent={floor} key={decal.decalUuid} decal={decal} />
|
||||
))}
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,21 +2,36 @@ import React, { useEffect, useMemo } from 'react';
|
||||
import { Vector3 } from 'three';
|
||||
import { Html } from '@react-three/drei';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useToggleView } from '../../../../store/builder/store';
|
||||
import { useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import Line from '../../line/line';
|
||||
import Point from '../../point/point';
|
||||
import FloorInstance from './Instance/floorInstance';
|
||||
import Floor2DInstance from './Instance/floor2DInstance';
|
||||
import useModuleStore from '../../../../store/useModuleStore';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
|
||||
function FloorInstances() {
|
||||
const { floorStore } = useSceneContext();
|
||||
const { floors } = floorStore();
|
||||
const { setSelectedFloor, selectedFloor } = useBuilderStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('floors: ', floors);
|
||||
}, [floors])
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView && activeModule === 'builder') {
|
||||
if (toolMode !== 'cursor') {
|
||||
if (selectedFloor) setSelectedFloor(null);
|
||||
}
|
||||
} else {
|
||||
if (selectedFloor) setSelectedFloor(null);
|
||||
}
|
||||
}, [toggleView, toolMode, activeModule, selectedFloor]);
|
||||
|
||||
const allPoints = useMemo(() => {
|
||||
const points: Point[] = [];
|
||||
const seenUuids = new Set<string>();
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getUserData } from '../../../../functions/getUserData';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceFloor from './referenceFloor';
|
||||
|
||||
// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
|
||||
function FloorCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -120,23 +120,25 @@ function FloorCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
@@ -174,23 +176,25 @@ function FloorCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
@@ -238,23 +242,25 @@ function FloorCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
}
|
||||
setTempPoints([]);
|
||||
|
||||
@@ -10,7 +10,7 @@ import FloorInstances from './Instances/floorInstances';
|
||||
import { getFloorsApi } from '../../../services/factoryBuilder/floor/getFloorsApi';
|
||||
|
||||
function FloorGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { activeTool } = useActiveTool();
|
||||
@@ -21,11 +21,11 @@ function FloorGroup() {
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
if (toggleView || activeModule !== 'builder') {
|
||||
setSelectedFloor(null);
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}, [togglView, activeModule, activeTool])
|
||||
}, [toggleView, activeModule, activeTool])
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId && selectedVersion) {
|
||||
|
||||
@@ -13,14 +13,14 @@ import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCurso
|
||||
import { useSelectedPoints } from '../../../store/simulation/useSimulationStore';
|
||||
import { calculateAssetTransformationOnWall } from '../wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall';
|
||||
|
||||
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
// import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
// import { deleteWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||
import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||
import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
import { deleteWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
|
||||
interface LineProps {
|
||||
points: [Point, Point];
|
||||
@@ -120,43 +120,48 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (projectId && asset) {
|
||||
|
||||
removeWallAsset(asset.modelUuid);
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
|
||||
}
|
||||
})
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallApi(projectId, selectedVersion?.versionId || '', removedWall.wallUuid);
|
||||
deleteWallApi(projectId, selectedVersion?.versionId || '', removedWall.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallUuid: removedWall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallUuid: removedWall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
|
||||
push2D({
|
||||
type: 'Draw',
|
||||
actions: [
|
||||
@@ -180,22 +185,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (removedFloors.length > 0) {
|
||||
removedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -218,22 +226,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (updatedFloors.length > 0) {
|
||||
updatedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -263,22 +274,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (removedZones.length > 0) {
|
||||
removedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -301,22 +315,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
if (updatedZones.length > 0) {
|
||||
updatedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -435,40 +452,47 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
});
|
||||
|
||||
if (projectId && updatedWallAsset) {
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
// API
|
||||
|
||||
// SOCKET
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
})
|
||||
|
||||
if (initialPositions.walls && initialPositions.walls.length > 0) {
|
||||
@@ -495,22 +519,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
|
||||
if (updatedFloors.length > 0 && projectId) {
|
||||
updatedFloors.forEach(updatedFloor => {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
})
|
||||
|
||||
if (initialPositions.floors && initialPositions.floors.length > 0) {
|
||||
@@ -537,22 +564,25 @@ function Line({ points }: Readonly<LineProps>) {
|
||||
|
||||
if (updatedZones.length > 0 && projectId) {
|
||||
updatedZones.forEach(updatedZone => {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: updatedZone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: updatedZone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
})
|
||||
|
||||
if (initialPositions.zones && initialPositions.zones.length > 0) {
|
||||
|
||||
@@ -11,16 +11,16 @@ import { useParams } from 'react-router-dom';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
|
||||
// import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||
// import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
// import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
// import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||
// import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||
// import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
// import { deleteWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||
import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi';
|
||||
import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi';
|
||||
import { upsertZoneApi } from '../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
|
||||
import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
import { deleteWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCursors';
|
||||
@@ -190,22 +190,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||
if (updatedAisles.length > 0 && projectId) {
|
||||
updatedAisles.forEach((updatedAisle) => {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: updatedAisle.aisleUuid,
|
||||
points: updatedAisle.points,
|
||||
type: updatedAisle.type
|
||||
})
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: updatedAisle.aisleUuid,
|
||||
points: updatedAisle.points,
|
||||
type: updatedAisle.type
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (initialStates.aisles && initialStates.aisles.length > 0) {
|
||||
@@ -244,40 +247,47 @@ function Point({ point }: { readonly point: Point }) {
|
||||
});
|
||||
|
||||
if (projectId && updatedWallAsset) {
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
// API
|
||||
|
||||
// SOCKET
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: updatedWall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -301,22 +311,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
||||
if (updatedFloors && updatedFloors.length > 0 && projectId) {
|
||||
updatedFloors.forEach((updatedFloor) => {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: updatedFloor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -340,22 +353,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
const updatedZones = getZonesByPointId(point.pointUuid);
|
||||
if (updatedZones && updatedZones.length > 0 && projectId) {
|
||||
updatedZones.forEach((updatedZone) => {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: updatedZone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: updatedZone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -388,23 +404,26 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (removedAisles.length > 0) {
|
||||
removedAisles.forEach(aisle => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
|
||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:model-aisle:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-aisle:delete', data);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -436,44 +455,50 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (projectId && asset) {
|
||||
|
||||
removeWallAsset(asset.modelUuid);
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -501,22 +526,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (removedFloors.length > 0) {
|
||||
removedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -539,22 +567,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (updatedFloors.length > 0) {
|
||||
updatedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -583,22 +614,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (removedZones.length > 0) {
|
||||
removedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -621,22 +655,25 @@ function Point({ point }: { readonly point: Point }) {
|
||||
if (updatedZones.length > 0) {
|
||||
updatedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useToggleView, useWallVisibility } from '../../../../../store/builder/s
|
||||
import { useBuilderStore } from '../../../../../store/builder/useBuilderStore';
|
||||
import * as Constants from '../../../../../types/world/worldConstants';
|
||||
|
||||
import DecalInstance from '../../../Decal/decalInstance';
|
||||
import DecalInstance from '../../../Decal/decalInstance/decalInstance';
|
||||
|
||||
import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png';
|
||||
import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
@@ -21,7 +21,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
const { wallAssets, getWallAssetsByWall, setVisibility } = wallAssetStore();
|
||||
const assets = getWallAssetsByWall(wall.wallUuid);
|
||||
const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { camera } = useThree();
|
||||
const { wallVisibility } = useWallVisibility();
|
||||
@@ -118,10 +118,11 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
>
|
||||
{(assets.length > 0 || (walls[0].wallUuid === wall.wallUuid && wallAssets.length > 0)) ?
|
||||
<Base
|
||||
name={`BaseWall${wall.wallUuid}`}
|
||||
castShadow
|
||||
receiveShadow
|
||||
ref={meshRef}
|
||||
geometry={geometry}
|
||||
geometry={visible ? geometry : new THREE.BoxGeometry(0, 0)}
|
||||
position={[centerX, centerY, centerZ]}
|
||||
rotation={[0, -angle, 0]}
|
||||
userData={wall}
|
||||
@@ -154,7 +155,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
userData={wall}
|
||||
name={`WallReference_${wall.wallUuid}`}
|
||||
onDoubleClick={(e) => {
|
||||
if (visible && !togglView && activeModule === 'builder') {
|
||||
if (visible && !toggleView && activeModule === 'builder') {
|
||||
if (e.object.userData.wallUuid) {
|
||||
e.stopPropagation();
|
||||
setSelectedWall(e.object);
|
||||
@@ -171,7 +172,7 @@ function Wall({ wall }: { readonly wall: Wall }) {
|
||||
<MeshDiscardMaterial />
|
||||
|
||||
{wall.decals.map((decal) => (
|
||||
<DecalInstance zPosition={wall.wallThickness / 2 + 0.001} visible={visible} key={decal.decalUuid} decal={decal} />
|
||||
<DecalInstance parent={wall} visible={visible} key={decal.decalUuid} decal={decal} />
|
||||
))}
|
||||
</mesh>
|
||||
</mesh>
|
||||
|
||||
@@ -2,8 +2,9 @@ import React, { useEffect, useMemo } from 'react';
|
||||
import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three';
|
||||
import { Html, Extrude } from '@react-three/drei';
|
||||
import { useLoader } from '@react-three/fiber';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useToggleView } from '../../../../store/builder/store';
|
||||
import { useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useWallClassification } from './instance/helpers/useWallClassification';
|
||||
import Line from '../../line/line';
|
||||
import Point from '../../point/point';
|
||||
@@ -12,17 +13,31 @@ import * as Constants from '../../../../types/world/worldConstants';
|
||||
|
||||
import texturePath from "../../../../assets/textures/floor/white.png";
|
||||
import texturePathDark from "../../../../assets/textures/floor/black.png";
|
||||
import useModuleStore from '../../../../store/useModuleStore';
|
||||
|
||||
function WallInstances() {
|
||||
const { wallStore } = useSceneContext();
|
||||
const { setSelectedWall, selectedWall } = useBuilderStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { walls } = wallStore();
|
||||
const { rooms } = useWallClassification(walls);
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('walls: ', walls);
|
||||
}, [walls])
|
||||
|
||||
useEffect(() => {
|
||||
if (!toggleView && activeModule === 'builder') {
|
||||
if (toolMode !== 'cursor') {
|
||||
if (selectedWall) setSelectedWall(null);
|
||||
}
|
||||
} else {
|
||||
if (selectedWall) setSelectedWall(null);
|
||||
}
|
||||
}, [toggleView, toolMode, activeModule, selectedWall]);
|
||||
|
||||
const allPoints = useMemo(() => {
|
||||
const points: Point[] = [];
|
||||
const seenUuids = new Set<string>();
|
||||
|
||||
@@ -12,8 +12,8 @@ import getClosestIntersection from '../../line/helpers/getClosestIntersection';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceWall from './referenceWall';
|
||||
|
||||
// import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
// import { deleteWallApi } from '../../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
import { upsertWallApi } from '../../../../services/factoryBuilder/wall/upsertWallApi';
|
||||
import { deleteWallApi } from '../../../../services/factoryBuilder/wall/deleteWallApi';
|
||||
|
||||
function WallCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -94,23 +94,26 @@ function WallCreator() {
|
||||
removeWall(wall.wallUuid);
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
|
||||
}
|
||||
|
||||
const point1: Point = {
|
||||
@@ -147,24 +150,27 @@ function WallCreator() {
|
||||
|
||||
addWall(wall2);
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall2);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall2);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: wall2,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallData: wall2,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
|
||||
const wall3: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point2, newPoint],
|
||||
@@ -204,24 +210,27 @@ function WallCreator() {
|
||||
],
|
||||
})
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall3);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall3);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data2 = {
|
||||
wallData: wall3,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data2 = {
|
||||
wallData: wall3,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data2);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data2);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
setIsCreating(true);
|
||||
} else {
|
||||
@@ -237,24 +246,27 @@ function WallCreator() {
|
||||
|
||||
addWall(wall1);
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall1);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall1);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: wall1,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallData: wall1,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
|
||||
const wall2: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point1, newPoint],
|
||||
@@ -267,24 +279,27 @@ function WallCreator() {
|
||||
|
||||
addWall(wall2);
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall2);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall2);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data1 = {
|
||||
wallData: wall2,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data1 = {
|
||||
wallData: wall2,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data1);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data1);
|
||||
|
||||
const wall3: Wall = {
|
||||
wallUuid: THREE.MathUtils.generateUUID(),
|
||||
points: [point2, newPoint],
|
||||
@@ -328,24 +343,27 @@ function WallCreator() {
|
||||
],
|
||||
})
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall3);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall3);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data3 = {
|
||||
wallData: wall3,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data3 = {
|
||||
wallData: wall3,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data3);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data3);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
|
||||
@@ -411,24 +429,27 @@ function WallCreator() {
|
||||
],
|
||||
})
|
||||
|
||||
// API
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// if (projectId) {
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', wall);
|
||||
// }
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', wall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallData: wall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallData: wall,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:add', data);
|
||||
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import WallInstances from './Instances/wallInstances';
|
||||
import { getWallsApi } from '../../../services/factoryBuilder/wall/getWallsApi';
|
||||
|
||||
function WallGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { setSelectedWall, setSelectedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { activeTool } = useActiveTool();
|
||||
@@ -22,11 +22,11 @@ function WallGroup() {
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
if (toggleView || activeModule !== 'builder') {
|
||||
setSelectedWall(null);
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}, [togglView, activeModule, activeTool])
|
||||
}, [toggleView, activeModule, activeTool])
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId && selectedVersion) {
|
||||
|
||||
@@ -18,10 +18,10 @@ const calculateAssetTransformationOnWall = (
|
||||
|
||||
const projection = initialWallNormalized.clone().multiplyScalar(dotProduct);
|
||||
const perpendicular = new THREE.Vector3().subVectors(assetVector, projection);
|
||||
const distanceFromWall = perpendicular.length();
|
||||
const distanceInWall = perpendicular.length();
|
||||
|
||||
const crossProduct = new THREE.Vector3().crossVectors(initialWallNormalized, perpendicular).y;
|
||||
const signedDistance = distanceFromWall * (crossProduct >= 0 ? 1 : -1);
|
||||
const signedDistance = distanceInWall * (crossProduct >= 0 ? 1 : -1);
|
||||
|
||||
const percentage = Math.max(0, Math.min(1, dotProduct / initialWallLength));
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ import { useVersionContext } from '../../../version/versionContext';
|
||||
import { getUserData } from '../../../../../functions/getUserData';
|
||||
import closestPointOnLineSegment from '../../../line/helpers/getClosestPointOnLineSegment';
|
||||
|
||||
// import { upsertWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
// import { deleteWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
import { upsertWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
import { deleteWallAssetApi } from '../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi';
|
||||
|
||||
function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
@@ -23,7 +23,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const { raycaster, pointer, camera, scene, controls, gl } = useThree();
|
||||
const { wallStore, wallAssetStore } = useSceneContext();
|
||||
const { walls, getWallById } = wallStore();
|
||||
const { updateWallAsset, removeWallAsset } = wallAssetStore();
|
||||
const { updateWallAsset, removeWallAsset, getWallAssetById } = wallAssetStore();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { activeModule } = useModuleStore();
|
||||
@@ -116,52 +116,35 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onPointerUp = (e: PointerEvent) => {
|
||||
draggingRef.current = false;
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
if (draggingRef.current) {
|
||||
draggingRef.current = false;
|
||||
if (controls) {
|
||||
(controls as any).enabled = true;
|
||||
}
|
||||
|
||||
if (selectedWallAsset) {
|
||||
pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
const intersect = intersects.find((i: any) => i.object.name.includes('WallReference'));
|
||||
|
||||
if (intersect && intersect.object.userData.wallUuid && selectedWallAsset.userData.modelUuid === wallAsset.modelUuid) {
|
||||
const newPoint = closestPointOnLineSegment(
|
||||
new THREE.Vector3(intersect.point.x, 0, intersect.point.z),
|
||||
new THREE.Vector3(...intersect.object.userData.points[0].position),
|
||||
new THREE.Vector3(...intersect.object.userData.points[1].position)
|
||||
);
|
||||
|
||||
const wallRotation = intersect.object.rotation.clone();
|
||||
|
||||
const updatedWallAsset = updateWallAsset(wallAsset.modelUuid, {
|
||||
wallUuid: intersect.object.userData.wallUuid,
|
||||
position: [newPoint.x, wallAsset.wallAssetType === 'fixedMove' ? 0 : intersect.point.y, newPoint.z],
|
||||
rotation: [wallRotation.x, wallRotation.y, wallRotation.z],
|
||||
});
|
||||
if (selectedWallAsset) {
|
||||
const updatedWallAsset = getWallAssetById(wallAsset.modelUuid);
|
||||
|
||||
if (projectId && updatedWallAsset) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,24 +196,26 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
const removedWallAsset = removeWallAsset(wallAsset.modelUuid);
|
||||
|
||||
if (projectId && removedWallAsset) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallAssetApi(projectId, selectedVersion?.versionId || '', removedWallAsset.modelUuid, removedWallAsset.wallUuid);
|
||||
deleteWallAssetApi(projectId, selectedVersion?.versionId || '', removedWallAsset.modelUuid, removedWallAsset.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: removedWallAsset.modelUuid,
|
||||
wallUuid: removedWallAsset.wallUuid
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: removedWallAsset.modelUuid,
|
||||
wallUuid: removedWallAsset.wallUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
|
||||
}
|
||||
}
|
||||
}, [activeTool, activeModule, deletableWallAsset, socket])
|
||||
@@ -307,7 +292,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
||||
setSelectedWallAsset(null);
|
||||
}
|
||||
}}
|
||||
onPointerOver={(e) => {
|
||||
onPointerEnter={(e) => {
|
||||
if (!toggleView) {
|
||||
e.stopPropagation();
|
||||
let currentObject = e.object as THREE.Object3D;
|
||||
|
||||
@@ -9,12 +9,12 @@ import { useVersionContext } from '../version/versionContext';
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import closestPointOnLineSegment from '../line/helpers/getClosestPointOnLineSegment';
|
||||
|
||||
// import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
import { upsertWallAssetApi } from '../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi';
|
||||
|
||||
function WallAssetCreator() {
|
||||
const { socket } = useSocketStore();
|
||||
const { pointer, camera, raycaster, scene, gl } = useThree();
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { wallAssetStore } = useSceneContext();
|
||||
const { addWallAsset } = wallAssetStore();
|
||||
@@ -62,29 +62,31 @@ function WallAssetCreator() {
|
||||
|
||||
addWallAsset(newWallAsset);
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', newWallAsset);
|
||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || '', newWallAsset);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallAssetData: newWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallAssetData: newWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!togglView && activeModule === 'builder') {
|
||||
if (!toggleView && activeModule === 'builder') {
|
||||
canvasElement.addEventListener('drop', onDrop);
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ function WallAssetCreator() {
|
||||
canvasElement.removeEventListener('drop', onDrop);
|
||||
};
|
||||
|
||||
}, [gl, camera, togglView, activeModule, socket, selectedItem, setSelectedItem]);
|
||||
}, [gl, camera, toggleView, activeModule, socket, selectedItem, setSelectedItem]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useActiveTool, useToggleView } from '../../../store/builder/store';
|
||||
import { useToggleView, useToolMode } from '../../../store/builder/store';
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
@@ -10,10 +10,10 @@ import WallAssetInstances from './Instances/wallAssetInstances'
|
||||
import { getWallAssetsApi } from '../../../services/factoryBuilder/asset/wallAsset/getWallAssetsApi';
|
||||
|
||||
function WallAssetGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { setSelectedFloorAsset, setDeletableWallAsset } = useBuilderStore();
|
||||
const { toggleView } = useToggleView();
|
||||
const { setSelectedWallAsset, setDeletableWallAsset } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { toolMode } = useToolMode();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { wallAssetStore } = useSceneContext();
|
||||
@@ -21,11 +21,11 @@ function WallAssetGroup() {
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
setSelectedFloorAsset(null);
|
||||
if (toggleView || activeModule !== 'builder' || toolMode !== 'cursor') {
|
||||
setSelectedWallAsset(null);
|
||||
}
|
||||
setDeletableWallAsset(null);
|
||||
}, [togglView, activeModule, activeTool])
|
||||
}, [toggleView, activeModule, toolMode])
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId && selectedVersion) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getUserData } from '../../../../functions/getUserData';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceZone from './referenceZone';
|
||||
|
||||
// import { upsertZoneApi } from '../../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
import { upsertZoneApi } from '../../../../services/factoryBuilder/zone/upsertZoneApi';
|
||||
|
||||
function ZoneCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -33,7 +33,6 @@ function ZoneCreator() {
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const { zoneColor, zoneHeight, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
@@ -119,23 +118,25 @@ function ZoneCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
@@ -171,23 +172,25 @@ function ZoneCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
@@ -233,23 +236,25 @@ function ZoneCreator() {
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
|
||||
}
|
||||
}
|
||||
setTempPoints([]);
|
||||
|
||||
@@ -11,7 +11,7 @@ import ZoneInstances from './Instances/zoneInstances';
|
||||
import { getZonesApi } from '../../../services/factoryBuilder/zone/getZonesApi';
|
||||
|
||||
function ZoneGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { toggleView } = useToggleView();
|
||||
const { setSelectedZone } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { activeTool } = useActiveTool();
|
||||
@@ -22,10 +22,10 @@ function ZoneGroup() {
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
if (toggleView || activeModule !== 'builder') {
|
||||
setSelectedZone(null);
|
||||
}
|
||||
}, [togglView, activeModule, activeTool])
|
||||
}, [toggleView, activeModule, activeTool])
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId && selectedVersion) {
|
||||
|
||||
@@ -5,12 +5,16 @@ export default function SocketResponses() {
|
||||
const { socket } = useSocketStore();
|
||||
|
||||
useEffect(() => {
|
||||
socket.on("v1:model-asset:response:add", (data: any) => {
|
||||
// console.log('data: ', data);
|
||||
});
|
||||
if (socket) {
|
||||
socket.on("v1:model-asset:response:add", (data: any) => {
|
||||
// console.log('data: ', data);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
socket.off("v1:model-asset:response:add");
|
||||
if (socket) {
|
||||
socket.off("v1:model-asset:response:add");
|
||||
}
|
||||
}
|
||||
}, [socket])
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useKeyboardControls } from "@react-three/drei";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import { useCamMode, useToggleView } from "../../../store/builder/store";
|
||||
import { useKeyboardControls } from "@react-three/drei";
|
||||
import switchToThirdPerson from "./switchToThirdPerson";
|
||||
import switchToFirstPerson from "./switchToFirstPerson";
|
||||
|
||||
import switchToThirdPerson from "./functions/switchToThirdPerson";
|
||||
import switchToFirstPerson from "./functions/switchToFirstPerson";
|
||||
import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys";
|
||||
import { firstPersonCamera } from "./firstPersonCamera";
|
||||
import { firstPersonCamera } from "./functions/firstPersonCamera";
|
||||
|
||||
const CamMode: React.FC = () => {
|
||||
const { camMode, setCamMode } = useCamMode();
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
|
||||
interface FirstPersonCameraProps {
|
||||
setIsTransitioning?: (value: boolean) => void;
|
||||
state: any;
|
||||
}
|
||||
|
||||
interface FirstPersonCameraParams extends FirstPersonCameraProps {
|
||||
camMode: string;
|
||||
setCamMode: (mode: string) => void;
|
||||
switchToFirstPerson: (controls: any, camera: any) => Promise<void>;
|
||||
switchToThirdPerson: (controls: any, camera: any) => Promise<void>;
|
||||
}
|
||||
|
||||
export async function firstPersonCamera({
|
||||
setIsTransitioning,
|
||||
state,
|
||||
camMode,
|
||||
setCamMode,
|
||||
switchToFirstPerson,
|
||||
switchToThirdPerson
|
||||
}: FirstPersonCameraParams): Promise<void> {
|
||||
setIsTransitioning && setIsTransitioning(true);
|
||||
|
||||
state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse;
|
||||
state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse;
|
||||
state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse;
|
||||
state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse;
|
||||
|
||||
if (camMode === "ThirdPerson") {
|
||||
setCamMode("FirstPerson");
|
||||
await switchToFirstPerson(state.controls, state.camera);
|
||||
} else if (camMode === "FirstPerson") {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
|
||||
setIsTransitioning && setIsTransitioning(false);
|
||||
}
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
interface FirstPersonCameraProps {
|
||||
setIsTransitioning?: (value: boolean) => void;
|
||||
state: any;
|
||||
}
|
||||
|
||||
interface FirstPersonCameraParams extends FirstPersonCameraProps {
|
||||
camMode: string;
|
||||
setCamMode: (mode: string) => void;
|
||||
switchToFirstPerson: (controls: any, camera: any) => Promise<void>;
|
||||
switchToThirdPerson: (controls: any, camera: any) => Promise<void>;
|
||||
}
|
||||
|
||||
export async function firstPersonCamera({
|
||||
setIsTransitioning,
|
||||
state,
|
||||
camMode,
|
||||
setCamMode,
|
||||
switchToFirstPerson,
|
||||
switchToThirdPerson
|
||||
}: FirstPersonCameraParams): Promise<void> {
|
||||
setIsTransitioning && setIsTransitioning(true);
|
||||
|
||||
state.controls.mouseButtons.left = CONSTANTS.controlsTransition.leftMouse;
|
||||
state.controls.mouseButtons.right = CONSTANTS.controlsTransition.rightMouse;
|
||||
state.controls.mouseButtons.wheel = CONSTANTS.controlsTransition.wheelMouse;
|
||||
state.controls.mouseButtons.middle = CONSTANTS.controlsTransition.middleMouse;
|
||||
|
||||
if (camMode === "ThirdPerson") {
|
||||
setCamMode("FirstPerson");
|
||||
await switchToFirstPerson(state.controls, state.camera);
|
||||
} else if (camMode === "FirstPerson") {
|
||||
setCamMode("ThirdPerson");
|
||||
await switchToThirdPerson(state.controls, state.camera);
|
||||
}
|
||||
|
||||
setIsTransitioning && setIsTransitioning(false);
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
export default async function switchToFirstPerson(
|
||||
controls: any,
|
||||
camera: any
|
||||
) {
|
||||
if (!controls) return;
|
||||
|
||||
const cameraDirection = new THREE.Vector3();
|
||||
camera.getWorldDirection(cameraDirection);
|
||||
cameraDirection.normalize();
|
||||
|
||||
await controls.setPosition(camera.position.x, 2, camera.position.z, true);
|
||||
controls.setTarget(camera.position.x, 2, camera.position.z, true);
|
||||
controls.mouseButtons.left = CONSTANTS.firstPersonControls.leftMouse;
|
||||
controls.lockPointer();
|
||||
|
||||
controls.azimuthRotateSpeed = CONSTANTS.firstPersonControls.azimuthRotateSpeed;
|
||||
controls.polarRotateSpeed = CONSTANTS.firstPersonControls.polarRotateSpeed;
|
||||
controls.truckSpeed = CONSTANTS.firstPersonControls.truckSpeed;
|
||||
controls.minDistance = CONSTANTS.firstPersonControls.minDistance;
|
||||
controls.maxDistance = CONSTANTS.firstPersonControls.maxDistance;
|
||||
controls.maxPolarAngle = CONSTANTS.firstPersonControls.maxPolarAngle;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function switchToFirstPerson(
|
||||
controls: any,
|
||||
camera: any
|
||||
) {
|
||||
if (!controls) return;
|
||||
|
||||
const cameraDirection = new THREE.Vector3();
|
||||
camera.getWorldDirection(cameraDirection);
|
||||
cameraDirection.normalize();
|
||||
|
||||
await controls.setPosition(camera.position.x, 2, camera.position.z, true);
|
||||
controls.setTarget(camera.position.x, 2, camera.position.z, true);
|
||||
controls.mouseButtons.left = CONSTANTS.firstPersonControls.leftMouse;
|
||||
controls.lockPointer();
|
||||
|
||||
controls.azimuthRotateSpeed = CONSTANTS.firstPersonControls.azimuthRotateSpeed;
|
||||
controls.polarRotateSpeed = CONSTANTS.firstPersonControls.polarRotateSpeed;
|
||||
controls.truckSpeed = CONSTANTS.firstPersonControls.truckSpeed;
|
||||
controls.minDistance = CONSTANTS.firstPersonControls.minDistance;
|
||||
controls.maxDistance = CONSTANTS.firstPersonControls.maxDistance;
|
||||
controls.maxPolarAngle = CONSTANTS.firstPersonControls.maxPolarAngle;
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
export default async function switchToThirdPerson(
|
||||
controls: any,
|
||||
camera: any
|
||||
) {
|
||||
if (!controls) return;
|
||||
controls.mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
|
||||
controls.mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
|
||||
controls.mouseButtons.middle = CONSTANTS.thirdPersonControls.middleMouse;
|
||||
controls.mouseButtons.wheel = CONSTANTS.thirdPersonControls.wheelMouse;
|
||||
controls.unlockPointer();
|
||||
|
||||
const cameraDirection = new THREE.Vector3();
|
||||
camera.getWorldDirection(cameraDirection);
|
||||
const targetOffset = cameraDirection.multiplyScalar(CONSTANTS.thirdPersonControls.targetOffset);
|
||||
const targetPosition = new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z).add(targetOffset);
|
||||
|
||||
controls.setPosition(camera.position.x, CONSTANTS.thirdPersonControls.cameraHeight, camera.position.z, true);
|
||||
controls.setTarget(targetPosition.x, 0, targetPosition.z, true);
|
||||
|
||||
controls.azimuthRotateSpeed = CONSTANTS.thirdPersonControls.azimuthRotateSpeed;
|
||||
controls.polarRotateSpeed = CONSTANTS.thirdPersonControls.polarRotateSpeed;
|
||||
controls.truckSpeed = CONSTANTS.thirdPersonControls.truckSpeed;
|
||||
controls.minDistance = CONSTANTS.threeDimension.minDistance;
|
||||
controls.maxDistance = CONSTANTS.thirdPersonControls.maxDistance;
|
||||
controls.maxPolarAngle = CONSTANTS.thirdPersonControls.maxPolarAngle;
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
export default async function switchToThirdPerson(
|
||||
controls: any,
|
||||
camera: any
|
||||
) {
|
||||
if (!controls) return;
|
||||
controls.mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
|
||||
controls.mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
|
||||
controls.mouseButtons.middle = CONSTANTS.thirdPersonControls.middleMouse;
|
||||
controls.mouseButtons.wheel = CONSTANTS.thirdPersonControls.wheelMouse;
|
||||
controls.unlockPointer();
|
||||
|
||||
const cameraDirection = new THREE.Vector3();
|
||||
camera.getWorldDirection(cameraDirection);
|
||||
const targetOffset = cameraDirection.multiplyScalar(CONSTANTS.thirdPersonControls.targetOffset);
|
||||
const targetPosition = new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z).add(targetOffset);
|
||||
|
||||
controls.setPosition(camera.position.x, CONSTANTS.thirdPersonControls.cameraHeight, camera.position.z, true);
|
||||
controls.setTarget(targetPosition.x, 0, targetPosition.z, true);
|
||||
|
||||
controls.azimuthRotateSpeed = CONSTANTS.thirdPersonControls.azimuthRotateSpeed;
|
||||
controls.polarRotateSpeed = CONSTANTS.thirdPersonControls.polarRotateSpeed;
|
||||
controls.truckSpeed = CONSTANTS.thirdPersonControls.truckSpeed;
|
||||
controls.minDistance = CONSTANTS.threeDimension.minDistance;
|
||||
controls.maxDistance = CONSTANTS.thirdPersonControls.maxDistance;
|
||||
controls.maxPolarAngle = CONSTANTS.thirdPersonControls.maxPolarAngle;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Socket } from "socket.io-client";
|
||||
import * as THREE from "three";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { CameraControls } from "@react-three/drei";
|
||||
import { setCameraApi } from "../../../../services/factoryBuilder/camera/setCameraApi";
|
||||
|
||||
export default function updateCamPosition(
|
||||
controls: React.RefObject<CameraControls>,
|
||||
socket: Socket,
|
||||
position: THREE.Vector3,
|
||||
rotation: THREE.Euler,
|
||||
projectId?: string
|
||||
) {
|
||||
const { userId, organization } = getUserData();
|
||||
if (!controls.current || !projectId) return;
|
||||
const target = controls.current.getTarget(new THREE.Vector3());
|
||||
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
setCameraApi(
|
||||
projectId,
|
||||
position,
|
||||
new THREE.Vector3(target.x, 0, target.z),
|
||||
new THREE.Vector3(rotation.x, rotation.y, rotation.z),
|
||||
)
|
||||
} else {
|
||||
// SOCKET
|
||||
|
||||
const camData = {
|
||||
organization,
|
||||
userId: userId,
|
||||
position: position,
|
||||
target: new THREE.Vector3(target.x, 0, target.z),
|
||||
rotation: new THREE.Vector3(rotation.x, rotation.y, rotation.z),
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
};
|
||||
socket.emit("v1:Camera:set", camData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import type { CameraControls } from "@react-three/drei";
|
||||
|
||||
const CameraShortcutsControls = () => {
|
||||
const { camera, controls } = useThree();
|
||||
|
||||
const isTextInput = (element: Element | null): boolean =>
|
||||
element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement ||
|
||||
element?.getAttribute("contenteditable") === "true";
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (!controls) return;
|
||||
|
||||
const cc = controls as CameraControls;
|
||||
|
||||
// get current target
|
||||
const target = new THREE.Vector3();
|
||||
cc.getTarget(target);
|
||||
|
||||
const distance = camera.position.distanceTo(target);
|
||||
let pos: THREE.Vector3 | null = null;
|
||||
|
||||
const dir = new THREE.Vector3().subVectors(camera.position, target).normalize();
|
||||
|
||||
if (isTextInput(document.activeElement)) return;
|
||||
|
||||
switch (e.key) {
|
||||
case "1": // Front
|
||||
pos = new THREE.Vector3(0, 0, distance).add(target);
|
||||
break;
|
||||
case "3": // Right
|
||||
pos = new THREE.Vector3(distance, 0, 0).add(target);
|
||||
break;
|
||||
case "7": // Top
|
||||
pos = new THREE.Vector3(0, distance, 0).add(target);
|
||||
break;
|
||||
case "9": {
|
||||
// Opposite view logic
|
||||
if (Math.abs(dir.z) > Math.abs(dir.x) && Math.abs(dir.z) > Math.abs(dir.y)) {
|
||||
// Currently looking Front/Back → flip Z
|
||||
pos = new THREE.Vector3(0, 0, -Math.sign(dir.z) * distance).add(target);
|
||||
} else if (Math.abs(dir.x) > Math.abs(dir.z) && Math.abs(dir.x) > Math.abs(dir.y)) {
|
||||
// Currently looking Right/Left → flip X
|
||||
pos = new THREE.Vector3(-Math.sign(dir.x) * distance, 0, 0).add(target);
|
||||
} else {
|
||||
// Currently looking Top/Bottom → stay Top
|
||||
pos = new THREE.Vector3(0, distance, 0).add(target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos) {
|
||||
cc.setLookAt(
|
||||
pos.x, pos.y, pos.z, // camera position
|
||||
target.x, target.y, target.z, // keep same target
|
||||
true // smooth transition
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [controls, camera]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default CameraShortcutsControls;
|
||||
@@ -4,7 +4,7 @@ import * as THREE from 'three';
|
||||
import { PerspectiveCamera, OrthographicCamera, CameraControls } from '@react-three/drei';
|
||||
import { useParams } from "react-router-dom";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useToggleView } from "../../../store/builder/store";
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function SwitchView() {
|
||||
(controls as any).mouseButtons.right = CONSTANTS.twoDimension.rightMouse;
|
||||
} else {
|
||||
try {
|
||||
getCamera(organization, localStorage.getItem('userId')!, projectId).then((data) => {
|
||||
getCameraApi(organization, localStorage.getItem('userId')!, projectId).then((data) => {
|
||||
if (data && data.position && data.target) {
|
||||
(controls as CameraControls)?.setPosition(data.position.x, data.position.y, data.position.z);
|
||||
(controls as CameraControls)?.setTarget(data.target.x, data.target.y, data.target.z);
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Socket } from "socket.io-client";
|
||||
import * as THREE from "three";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
export default function updateCamPosition(
|
||||
controls: any,
|
||||
socket: Socket,
|
||||
position: THREE.Vector3,
|
||||
rotation: THREE.Euler,
|
||||
projectId?: string
|
||||
) {
|
||||
const { userId, organization } = getUserData();
|
||||
if (!controls.current) return;
|
||||
const target = controls.current.getTarget(new THREE.Vector3());
|
||||
|
||||
const camData = {
|
||||
organization,
|
||||
userId: userId,
|
||||
position: position,
|
||||
target: new THREE.Vector3(target.x, 0, target.z),
|
||||
rotation: new THREE.Vector3(rotation.x, rotation.y, rotation.z),
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
};
|
||||
socket.emit("v1:Camera:set", camData);
|
||||
}
|
||||
@@ -1,15 +1,35 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { CameraControls, Html, ScreenSpace } from '@react-three/drei';
|
||||
import { useContextActionStore, useRenameModeStore, useSelectedAssets } from '../../../../store/builder/store';
|
||||
import ContextMenu from '../../../../components/ui/menu/contextMenu';
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { CameraControls, Html, ScreenSpace } from "@react-three/drei";
|
||||
import { useContextActionStore, useRenameModeStore, useToggleView, useToolMode, } from "../../../../store/builder/store";
|
||||
import ContextMenu from "../../../../components/ui/menu/contextMenu";
|
||||
import useModuleStore from "../../../../store/useModuleStore";
|
||||
import { useSceneContext } from "../../sceneContext";
|
||||
|
||||
function ContextControls() {
|
||||
const { gl, controls } = useThree();
|
||||
const [canRender, setCanRender] = useState(false);
|
||||
const [visibility, setVisibility] = useState({ rename: true, focus: true, flipX: true, flipZ: true, move: true, rotate: true, duplicate: true, copy: true, paste: true, modifier: false, group: false, array: false, delete: true, });
|
||||
const [visibility, setVisibility] = useState({
|
||||
rename: true,
|
||||
focus: true,
|
||||
flipX: true,
|
||||
flipZ: true,
|
||||
move: true,
|
||||
rotate: true,
|
||||
duplicate: true,
|
||||
copy: true,
|
||||
paste: true,
|
||||
modifier: false,
|
||||
group: false,
|
||||
array: false,
|
||||
delete: true,
|
||||
});
|
||||
const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
|
||||
const { selectedAssets } = useSelectedAssets();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { selectedAssets, movedObjects, rotatedObjects, duplicatedObjects, copiedObjects } = assetStore();
|
||||
const { setContextAction } = useContextActionStore();
|
||||
const { setIsRenameMode } = useRenameModeStore();
|
||||
const rightDrag = useRef(false);
|
||||
@@ -93,8 +113,11 @@ function ContextControls() {
|
||||
event.preventDefault();
|
||||
if (rightDrag.current) return;
|
||||
if (selectedAssets.length > 0) {
|
||||
setMenuPosition({ x: event.clientX - gl.domElement.width / 2, y: event.clientY - gl.domElement.height / 2 });
|
||||
setCanRender(true);
|
||||
setMenuPosition({ x: event.clientX - gl.domElement.width / 2, y: event.clientY - gl.domElement.height / 2, });
|
||||
setTimeout(() => {
|
||||
setCanRender(true);
|
||||
}, 0)
|
||||
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = false;
|
||||
}
|
||||
@@ -106,11 +129,11 @@ function ContextControls() {
|
||||
}
|
||||
};
|
||||
|
||||
if (selectedAssets.length > 0) {
|
||||
canvasElement.addEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.addEventListener('pointermove', onPointerMove);
|
||||
canvasElement.addEventListener('pointerup', onPointerUp);
|
||||
canvasElement.addEventListener('contextmenu', handleContextClick)
|
||||
if (selectedAssets.length > 0 && !toggleView && activeModule === "builder" && toolMode === 'cursor' && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0 && copiedObjects.length === 0) {
|
||||
canvasElement.addEventListener("pointerdown", onPointerDown);
|
||||
canvasElement.addEventListener("pointermove", onPointerMove);
|
||||
canvasElement.addEventListener("pointerup", onPointerUp);
|
||||
canvasElement.addEventListener("contextmenu", handleContextClick);
|
||||
} else {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
@@ -120,12 +143,12 @@ function ContextControls() {
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener('pointerdown', onPointerDown);
|
||||
canvasElement.removeEventListener('pointermove', onPointerMove);
|
||||
canvasElement.removeEventListener('pointerup', onPointerUp);
|
||||
canvasElement.removeEventListener('contextmenu', handleContextClick);
|
||||
canvasElement.removeEventListener("pointerdown", onPointerDown);
|
||||
canvasElement.removeEventListener("pointermove", onPointerMove);
|
||||
canvasElement.removeEventListener("pointerup", onPointerUp);
|
||||
canvasElement.removeEventListener("contextmenu", handleContextClick);
|
||||
};
|
||||
}, [gl, selectedAssets]);
|
||||
}, [controls, gl, selectedAssets, toggleView, activeModule, toolMode, duplicatedObjects, movedObjects, rotatedObjects, copiedObjects]);
|
||||
|
||||
const handleAssetRename = () => {
|
||||
setCanRender(false);
|
||||
@@ -134,67 +157,67 @@ function ContextControls() {
|
||||
}
|
||||
setContextAction("renameAsset");
|
||||
setIsRenameMode(true);
|
||||
}
|
||||
};
|
||||
const handleAssetFocus = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("focusAsset");
|
||||
}
|
||||
};
|
||||
const handleAssetMove = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("moveAsset")
|
||||
}
|
||||
setContextAction("moveAsset");
|
||||
};
|
||||
const handleAssetRotate = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("rotateAsset")
|
||||
}
|
||||
setContextAction("rotateAsset");
|
||||
};
|
||||
const handleAssetCopy = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("copyAsset")
|
||||
}
|
||||
setContextAction("copyAsset");
|
||||
};
|
||||
const handleAssetPaste = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("pasteAsset")
|
||||
}
|
||||
setContextAction("pasteAsset");
|
||||
};
|
||||
const handleAssetDelete = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("deleteAsset")
|
||||
}
|
||||
setContextAction("deleteAsset");
|
||||
};
|
||||
const handleAssetDuplicate = () => {
|
||||
setCanRender(false);
|
||||
if (controls) {
|
||||
(controls as CameraControls).enabled = true;
|
||||
}
|
||||
setContextAction("duplicateAsset")
|
||||
}
|
||||
setContextAction("duplicateAsset");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{canRender && (
|
||||
<ScreenSpace depth={1} >
|
||||
<ScreenSpace depth={1}>
|
||||
<Html
|
||||
style={{
|
||||
position: 'fixed',
|
||||
position: "fixed",
|
||||
top: menuPosition.y,
|
||||
left: menuPosition.x,
|
||||
zIndex: 1000
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<ContextMenu
|
||||
|
||||
@@ -3,22 +3,23 @@ import { useRef, useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
import { useSocketStore, useToggleView, useResetCamera } from "../../../store/builder/store";
|
||||
import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import updateCamPosition from "../camera/updateCameraPosition";
|
||||
|
||||
import CamMode from "../camera/camMode";
|
||||
import SwitchView from "../camera/switchView";
|
||||
import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D";
|
||||
import TransformControl from "./transformControls/transformControls";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
import ContextControls from "./contextControls/contextControls";
|
||||
import TransformControl from "./transformControls/transformControls";
|
||||
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
|
||||
import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D";
|
||||
import UndoRedo2DControls from "./undoRedoControls/undoRedo2D/undoRedo2DControls";
|
||||
import UndoRedo3DControls from "./undoRedoControls/undoRedo3D/undoRedo3DControls";
|
||||
import { useCameraShortcuts } from "../../../hooks/useCameraShortcuts";
|
||||
import CameraShortcutsControls from "../camera/shortcutsControls/cameraShortcutsControls";
|
||||
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { getCameraApi } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import { setCameraApi } from "../../../services/factoryBuilder/camera/setCameraApi";
|
||||
import updateCamPosition from "../camera/functions/updateCameraPosition";
|
||||
|
||||
export default function Controls() {
|
||||
const controlsRef = useRef<CameraControls>(null);
|
||||
@@ -36,7 +37,7 @@ export default function Controls() {
|
||||
(controlsRef.current as any).mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
|
||||
}
|
||||
|
||||
getCamera(organization, userId, projectId).then((data) => {
|
||||
getCameraApi(organization, userId, projectId).then((data) => {
|
||||
if (data && data.position && data.target) {
|
||||
controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
|
||||
controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
|
||||
@@ -48,21 +49,30 @@ export default function Controls() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (resetCamera) {
|
||||
if (resetCamera && projectId) {
|
||||
controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
|
||||
controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
|
||||
controlsRef.current?.rotateAzimuthTo(CONSTANTS.threeDimension.defaultAzimuth);
|
||||
|
||||
const camData = {
|
||||
organization,
|
||||
userId: userId,
|
||||
position: new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
|
||||
target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
|
||||
rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
|
||||
socketId: socket.id,
|
||||
projectId
|
||||
};
|
||||
socket.emit('v1:Camera:set', camData)
|
||||
if (!socket?.connected) {
|
||||
setCameraApi(
|
||||
projectId,
|
||||
new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
|
||||
new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
|
||||
new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
|
||||
)
|
||||
} else {
|
||||
const camData = {
|
||||
organization,
|
||||
userId: userId,
|
||||
position: new THREE.Vector3(...CONSTANTS.threeDimension.defaultPosition),
|
||||
target: new THREE.Vector3(...CONSTANTS.threeDimension.defaultTarget),
|
||||
rotation: new THREE.Vector3(...CONSTANTS.threeDimension.defaultRotation),
|
||||
socketId: socket.id,
|
||||
projectId
|
||||
};
|
||||
socket.emit('v1:Camera:set', camData)
|
||||
}
|
||||
|
||||
setResetCamera(false);
|
||||
}
|
||||
@@ -75,7 +85,7 @@ export default function Controls() {
|
||||
let intervalId: NodeJS.Timeout | null = null;
|
||||
|
||||
const handleRest = () => {
|
||||
if (hasInteracted && controlsRef.current && state.camera.position && !toggleView) {
|
||||
if (hasInteracted && controlsRef.current && state.camera.position && !toggleView && socket) {
|
||||
const position = state.camera.position;
|
||||
if (position.x === 0 && position.y === 0 && position.z === 0) return;
|
||||
updateCamPosition(controlsRef, socket, position, state.camera.rotation, projectId);
|
||||
@@ -117,7 +127,6 @@ export default function Controls() {
|
||||
stopInterval();
|
||||
};
|
||||
}, [toggleView, state, socket]);
|
||||
useCameraShortcuts(controlsRef);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -140,6 +149,8 @@ export default function Controls() {
|
||||
|
||||
<CamMode />
|
||||
|
||||
<CameraShortcutsControls />
|
||||
|
||||
</CameraControls>
|
||||
|
||||
<SelectionControls3D />
|
||||
|
||||
@@ -11,10 +11,11 @@ import { useSelectedPoints } from "../../../../../store/simulation/useSimulation
|
||||
import useModuleStore from "../../../../../store/useModuleStore";
|
||||
import { calculateAssetTransformationOnWall } from "../../../../builder/wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall";
|
||||
|
||||
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||
// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||
import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||
import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||
import { upsertWallAssetApi } from "../../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi";
|
||||
|
||||
function MoveControls2D({
|
||||
movedObjects,
|
||||
@@ -270,21 +271,24 @@ function MoveControls2D({
|
||||
if (updatedAisles.length > 0 && projectId) {
|
||||
updatedAisles.forEach((updatedAisle) => {
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization,
|
||||
aisleUuid: updatedAisle.aisleUuid,
|
||||
points: updatedAisle.points,
|
||||
type: updatedAisle.type
|
||||
});
|
||||
socket.emit('v1:model-aisle:add', {
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization,
|
||||
aisleUuid: updatedAisle.aisleUuid,
|
||||
points: updatedAisle.points,
|
||||
type: updatedAisle.type
|
||||
});
|
||||
}
|
||||
|
||||
const old = initialStates[movedObject.uuid];
|
||||
if (old) {
|
||||
@@ -330,19 +334,22 @@ function MoveControls2D({
|
||||
});
|
||||
}
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-Wall:add', {
|
||||
wallData: updatedWall,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
socket.emit('v1:model-Wall:add', {
|
||||
wallData: updatedWall,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
}
|
||||
|
||||
const old = initialStates[movedObject.uuid];
|
||||
if (old) {
|
||||
@@ -371,19 +378,22 @@ function MoveControls2D({
|
||||
if (updatedFloors?.length && projectId) {
|
||||
updatedFloors.forEach(updatedFloor => {
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:model-Floor:add', {
|
||||
floorData: updatedFloor,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
socket.emit('v1:model-Floor:add', {
|
||||
floorData: updatedFloor,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
}
|
||||
|
||||
const updatedFloorsData = updatedFloors.map((floor) => {
|
||||
const originalFloor = Floors.find(f => f.floorUuid === floor.floorUuid) || floor;
|
||||
@@ -410,19 +420,22 @@ function MoveControls2D({
|
||||
if (updatedZones?.length && projectId) {
|
||||
updatedZones.forEach(updatedZone => {
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
socket.emit('v1:zone:add', {
|
||||
zoneData: updatedZone,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
socket.emit('v1:zone:add', {
|
||||
zoneData: updatedZone,
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId,
|
||||
organization
|
||||
});
|
||||
}
|
||||
|
||||
const updatedZonesData = updatedZones.map((zone) => {
|
||||
const originalZone = Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone;
|
||||
@@ -459,21 +472,24 @@ function MoveControls2D({
|
||||
rotation: updatedWallAsset.rotation
|
||||
});
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
// API
|
||||
|
||||
// upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || '', updatedWallAsset);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallAssetData: updatedWallAsset,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:add', data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,12 +14,13 @@ import { useSelectedPoints } from "../../../../../store/simulation/useSimulation
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
import MoveControls2D from "./moveControls2D";
|
||||
|
||||
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
||||
// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi";
|
||||
// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi";
|
||||
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
// import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi";
|
||||
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||
import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
|
||||
import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi";
|
||||
import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi";
|
||||
import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi";
|
||||
import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||
import { deleteWallAssetApi } from "../../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi";
|
||||
|
||||
const SelectionControls2D: React.FC = () => {
|
||||
const { camera, controls, gl, scene, pointer } = useThree();
|
||||
@@ -240,22 +241,25 @@ const SelectionControls2D: React.FC = () => {
|
||||
if (removedAisles.length > 0) {
|
||||
removedAisles.forEach(aisle => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
|
||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
aisleUuid: aisle.aisleUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:model-aisle:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-aisle:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -280,43 +284,49 @@ const SelectionControls2D: React.FC = () => {
|
||||
|
||||
removeWallAsset(asset.modelUuid);
|
||||
|
||||
// API
|
||||
if (!socket?.connected) {
|
||||
|
||||
// deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
// API
|
||||
|
||||
// SOCKET
|
||||
deleteWallAssetApi(projectId, selectedVersion?.versionId || '', asset.modelUuid, asset.wallUuid);
|
||||
} else {
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization,
|
||||
modelUuid: asset.modelUuid,
|
||||
wallUuid: asset.wallUuid
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:wall-asset:delete', data);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
wallUuid: wall.wallUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Wall:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -335,22 +345,25 @@ const SelectionControls2D: React.FC = () => {
|
||||
if (removedFloors.length > 0) {
|
||||
removedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorUuid: floor.floorUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -365,22 +378,25 @@ const SelectionControls2D: React.FC = () => {
|
||||
if (updatedFloors.length > 0) {
|
||||
updatedFloors.forEach(floor => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -400,22 +416,25 @@ const SelectionControls2D: React.FC = () => {
|
||||
if (removedZones.length > 0) {
|
||||
removedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneUuid: zone.zoneUuid,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:delete', data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -430,22 +449,25 @@ const SelectionControls2D: React.FC = () => {
|
||||
if (updatedZones.length > 0) {
|
||||
updatedZones.forEach(zone => {
|
||||
if (projectId) {
|
||||
if (!socket?.connected) {
|
||||
|
||||
// API
|
||||
// API
|
||||
|
||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
|
||||
} else {
|
||||
|
||||
// SOCKET
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
const data = {
|
||||
zoneData: zone,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
|
||||
socket.emit('v1:zone:add', data);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Line } from "@react-three/drei";
|
||||
import { useMemo } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useSelectedAssets } from "../../../../../store/builder/store";
|
||||
import { useMemo } from "react";
|
||||
import { Line } from "@react-three/drei";
|
||||
import { useSceneContext } from "../../../sceneContext";
|
||||
|
||||
interface BoundingBoxProps {
|
||||
boundingBoxRef?: any;
|
||||
@@ -26,7 +26,8 @@ const getBoxLines = (min: THREE.Vector3, max: THREE.Vector3) => [
|
||||
];
|
||||
|
||||
const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => {
|
||||
const { selectedAssets } = useSelectedAssets();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { selectedAssets } = assetStore();
|
||||
const savedTheme: string = localStorage.getItem("theme") || "light";
|
||||
|
||||
const boxes = useMemo(() => {
|
||||
@@ -88,9 +89,9 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) =>
|
||||
>
|
||||
<Line
|
||||
name="SelectionGroupBoundingBox"
|
||||
depthWrite={false}
|
||||
points={box.points}
|
||||
color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"}
|
||||
depthWrite={false}
|
||||
lineWidth={2.7}
|
||||
segments
|
||||
position={[box.position[0], box.position[1], box.position[2]]}
|
||||
|
||||