Compare commits
51 Commits
main
...
dev-r3f-wa
| Author | SHA1 | Date | |
|---|---|---|---|
| 64d086f808 | |||
| d6f6c4c901 | |||
| 0a039f34b1 | |||
| 364b643c72 | |||
| 1a9aef323a | |||
| 997775c27e | |||
| 943ad3ba49 | |||
| 7124a819b6 | |||
| 90df6c2b01 | |||
| fa6506c0be | |||
| 812a4f6aef | |||
| bfa4d7bbc6 | |||
| 540bb44e0c | |||
| 12f1dd1771 | |||
| edf76fa1c9 | |||
| c73bdf4556 | |||
| 64f0cdb148 | |||
| 04c302ea4c | |||
| b81aa10478 | |||
| 509f79db2c | |||
| 5003dc3504 | |||
| 1e88006780 | |||
| d926809dec | |||
| e5e92d2b9f | |||
| b4745451d2 | |||
| b3b0831a7f | |||
| 9696bc0f1e | |||
| d8a793c421 | |||
| 08208528a5 | |||
| 587ed6c9d7 | |||
| 982c92cf26 | |||
| 3ab5c6ee6a | |||
| 62e315e3d9 | |||
| 13a2648e83 | |||
| 7dc7b832ea | |||
| 5ae0ec0713 | |||
| 761d7bf704 | |||
| 17ec72e283 | |||
| a562a51025 | |||
| 81eb2d8193 | |||
| 3fe52e3e7c | |||
| a5afcd5757 | |||
| b49f431ebf | |||
| 385a64d307 | |||
| f593fcd578 | |||
| 329acbe397 | |||
| e38f17a18d | |||
| 88a470929e | |||
| 05a11c1184 | |||
| 012544a048 | |||
| d27c86a006 |
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import React, { useState, useRef, useEffect, act } from "react";
|
||||
import img from "../../assets/image/image.png";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
@@ -14,13 +14,15 @@ interface DashBoardCardProps {
|
||||
projectId: string;
|
||||
createdAt?: string;
|
||||
isViewed?: string;
|
||||
createdBy?: { _id: string, userName: string };
|
||||
handleDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleTrashDeleteProject?: (projectId: string) => Promise<void>;
|
||||
handleRestoreProject?: (projectId: string) => Promise<void>;
|
||||
handleDuplicateWorkspaceProject?: (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string
|
||||
thumbnail: string,
|
||||
userId?: string
|
||||
) => Promise<void>;
|
||||
handleDuplicateRecentProject?: (
|
||||
projectId: string,
|
||||
@@ -31,6 +33,7 @@ interface DashBoardCardProps {
|
||||
setIsSearchActive?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setRecentDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setProjectDuplicateData?: React.Dispatch<React.SetStateAction<Object>>;
|
||||
setActiveFolder?: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
type RelativeTimeFormatUnit = any;
|
||||
|
||||
@@ -45,8 +48,10 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
handleDuplicateWorkspaceProject,
|
||||
handleDuplicateRecentProject,
|
||||
createdAt,
|
||||
createdBy,
|
||||
setRecentDuplicateData,
|
||||
setProjectDuplicateData,
|
||||
setActiveFolder
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { setProjectName } = useProjectName();
|
||||
@@ -59,10 +64,18 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
const kebabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const navigateToProject = async (e: any) => {
|
||||
console.log('active: ', active);
|
||||
if (active && active == "trash") return;
|
||||
setLoadingProgress(1)
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
try {
|
||||
const viewProjects = await viewProject(organization, projectId, userId)
|
||||
console.log('viewProjects: ', viewProjects);
|
||||
console.log('projectName: ', projectName);
|
||||
setLoadingProgress(1)
|
||||
setProjectName(projectName);
|
||||
navigate(`/${projectId}`);
|
||||
} catch {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const handleOptionClick = async (option: string) => {
|
||||
@@ -81,11 +94,18 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
break;
|
||||
case "open in new tab":
|
||||
try {
|
||||
await viewProject(organization, projectId, userId);
|
||||
setProjectName(projectName);
|
||||
setIsKebabOpen(false);
|
||||
if (active === "shared" && createdBy) {
|
||||
console.log("ihreq");
|
||||
const newTab = await viewProject(organization, projectId, createdBy?._id);
|
||||
console.log('newTab: ', newTab);
|
||||
} else {
|
||||
const newTab = await viewProject(organization, projectId, userId);
|
||||
console.log('newTab: ', newTab);
|
||||
setProjectName(projectName);
|
||||
setIsKebabOpen(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error opening project in new tab:", error);
|
||||
|
||||
}
|
||||
window.open(`/${projectId}`, "_blank");
|
||||
break;
|
||||
@@ -100,13 +120,17 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
projectName,
|
||||
thumbnail,
|
||||
});
|
||||
await handleDuplicateWorkspaceProject(projectId, projectName, thumbnail);
|
||||
await handleDuplicateWorkspaceProject(projectId, projectName, thumbnail, userId);
|
||||
if (active === "shared" && setActiveFolder) {
|
||||
setActiveFolder("myProjects")
|
||||
}
|
||||
} else if (handleDuplicateRecentProject) {
|
||||
setRecentDuplicateData &&
|
||||
setRecentDuplicateData({
|
||||
projectId,
|
||||
projectName,
|
||||
thumbnail,
|
||||
userId
|
||||
});
|
||||
await handleDuplicateRecentProject(projectId, projectName, thumbnail);
|
||||
}
|
||||
@@ -127,7 +151,7 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
if (!projectId) return;
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
// console.log("projects: ", projects);
|
||||
if (!projects || !projects.Projects) return;
|
||||
let projectUuid = projects.Projects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
);
|
||||
@@ -172,6 +196,19 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
return "just now";
|
||||
}
|
||||
|
||||
const kebabOptionsMap: Record<string, string[]> = {
|
||||
default: ["rename", "delete", "duplicate", "open in new tab"],
|
||||
trash: ["restore", "delete"],
|
||||
shared: ["duplicate", "open in new tab"],
|
||||
};
|
||||
|
||||
const getOptions = () => {
|
||||
if (active === "trash") return kebabOptionsMap.trash;
|
||||
if (active === "shared") return kebabOptionsMap.shared;
|
||||
if (createdBy && createdBy?._id !== userId) return kebabOptionsMap.shared;
|
||||
return kebabOptionsMap.default;
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className="dashboard-card-container"
|
||||
@@ -211,13 +248,12 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
<div className="project-data">
|
||||
{active && active == "trash" ? `Trashed by you` : `Edited `}{" "}
|
||||
{getRelativeTime(createdAt)}
|
||||
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="users-list-container" ref={kebabRef}>
|
||||
<div className="user-profile">
|
||||
{userName ? userName.charAt(0).toUpperCase() : "A"}
|
||||
{(!createdBy) ? userName ? userName?.charAt(0).toUpperCase() : "A" : createdBy?.userName?.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
<button
|
||||
className="kebab-wrapper"
|
||||
@@ -231,29 +267,9 @@ const DashboardCard: React.FC<DashBoardCardProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isKebabOpen && active !== "trash" && (
|
||||
{isKebabOpen && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{["rename", "delete", "duplicate", "open in new tab"].map(
|
||||
(option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
title={""}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOptionClick(option);
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isKebabOpen && active && active == "trash" && (
|
||||
<div className="kebab-options-wrapper">
|
||||
{["restore", "delete"].map((option) => (
|
||||
{getOptions().map((option) => (
|
||||
<button
|
||||
key={option}
|
||||
className="option"
|
||||
|
||||
@@ -13,7 +13,7 @@ interface Project {
|
||||
_id: string;
|
||||
projectName: string;
|
||||
thumbnail: string;
|
||||
createdBy: string;
|
||||
createdBy: { _id: string, userName: string };
|
||||
projectUuid?: string;
|
||||
createdAt: string;
|
||||
isViewed?: string
|
||||
@@ -34,7 +34,8 @@ const DashboardHome: React.FC = () => {
|
||||
const fetchRecentProjects = async () => {
|
||||
try {
|
||||
const projects = await recentlyViewed(organization, userId);
|
||||
|
||||
console.log('projects: ', projects);
|
||||
|
||||
if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) {
|
||||
setRecentProjects(projects);
|
||||
}
|
||||
@@ -113,7 +114,6 @@ const DashboardHome: React.FC = () => {
|
||||
|
||||
const renderProjects = () => {
|
||||
const projectList = recentProjects[Object.keys(recentProjects)[0]];
|
||||
console.log('projectList: ', projectList);
|
||||
|
||||
if (!projectList?.length) {
|
||||
return <div className="empty-state">No recent projects found</div>;
|
||||
@@ -127,7 +127,8 @@ const DashboardHome: React.FC = () => {
|
||||
projectName={project.projectName}
|
||||
thumbnail={project.thumbnail}
|
||||
projectId={project._id}
|
||||
createdAt={project.isViewed}
|
||||
createdBy={project.createdBy}
|
||||
createdAt={project.createdAt}
|
||||
handleDeleteProject={handleDeleteProject}
|
||||
handleDuplicateRecentProject={handleDuplicateRecentProject}
|
||||
setRecentDuplicateData={setRecentDuplicateData}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { searchProject } from "../../services/dashboard/searchProjects";
|
||||
import { deleteProject } from "../../services/dashboard/deleteProject";
|
||||
import ProjectSocketRes from "./socket/projectSocketRes.dev";
|
||||
import { sharedWithMeProjects } from "../../services/dashboard/sharedWithMeProject";
|
||||
import { duplicateProject } from "../../services/dashboard/duplicateProject";
|
||||
|
||||
interface Project {
|
||||
_id: string;
|
||||
@@ -25,24 +27,13 @@ const DashboardProjects: React.FC = () => {
|
||||
const [workspaceProjects, setWorkspaceProjects] = useState<WorkspaceProjects>(
|
||||
{}
|
||||
);
|
||||
const [sharedwithMeProject, setSharedWithMeProjects] = useState<any>([])
|
||||
const [projectDuplicateData, setProjectDuplicateData] = useState<Object>({});
|
||||
const [isSearchActive, setIsSearchActive] = useState<boolean>(false);
|
||||
const [activeFolder, setActiveFolder] = useState<string>("myProjects");
|
||||
const { projectSocket } = useSocketStore();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
const fetchAllProjects = async () => {
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
|
||||
if (JSON.stringify(projects) !== JSON.stringify(workspaceProjects)) {
|
||||
setWorkspaceProjects(projects);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching projects:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleProjectsSearch = async (inputValue: string) => {
|
||||
if (!inputValue.trim()) {
|
||||
setIsSearchActive(false);
|
||||
@@ -55,6 +46,19 @@ const DashboardProjects: React.FC = () => {
|
||||
setWorkspaceProjects(searchedProject.message ? {} : searchedProject);
|
||||
};
|
||||
|
||||
const fetchAllProjects = async () => {
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
if (!projects || !projects.Projects) return;
|
||||
|
||||
if (JSON.stringify(projects) !== JSON.stringify(workspaceProjects)) {
|
||||
setWorkspaceProjects(projects);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching projects:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteProject = async (projectId: any) => {
|
||||
try {
|
||||
// const deletedProject = await deleteProject(
|
||||
@@ -96,18 +100,9 @@ const DashboardProjects: React.FC = () => {
|
||||
const handleDuplicateWorkspaceProject = async (
|
||||
projectId: string,
|
||||
projectName: string,
|
||||
thumbnail: string
|
||||
thumbnail: string,
|
||||
) => {
|
||||
// await handleDuplicateProjects({
|
||||
// userId,
|
||||
// organization,
|
||||
// projectId,
|
||||
// projectName,
|
||||
// projectSocket,
|
||||
// thumbnail,
|
||||
// setWorkspaceProjects,
|
||||
// setIsSearchActive
|
||||
// });
|
||||
|
||||
const duplicateProjectData = {
|
||||
userId,
|
||||
thumbnail,
|
||||
@@ -120,9 +115,7 @@ const DashboardProjects: React.FC = () => {
|
||||
|
||||
const renderProjects = () => {
|
||||
if (activeFolder !== "myProjects") return null;
|
||||
|
||||
const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]];
|
||||
|
||||
if (!projectList?.length) {
|
||||
return <div className="empty-state">No projects found</div>;
|
||||
}
|
||||
@@ -142,12 +135,49 @@ const DashboardProjects: React.FC = () => {
|
||||
));
|
||||
};
|
||||
|
||||
const renderSharedProjects = () => {
|
||||
return sharedwithMeProject?.map((project: any) => (
|
||||
<DashboardCard
|
||||
key={project._id}
|
||||
projectName={project.projectName}
|
||||
thumbnail={project.thumbnail}
|
||||
projectId={project._id}
|
||||
createdAt={project.createdAt}
|
||||
setIsSearchActive={setIsSearchActive}
|
||||
active="shared"
|
||||
createdBy={project.createdBy}
|
||||
setProjectDuplicateData={setProjectDuplicateData}
|
||||
handleDuplicateWorkspaceProject={handleDuplicateWorkspaceProject}
|
||||
setActiveFolder={setActiveFolder}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
const sharedProject = async () => {
|
||||
try {
|
||||
const sharedWithMe = await sharedWithMeProjects();
|
||||
console.log('sharedWithMe: ', sharedWithMe);
|
||||
setSharedWithMeProjects(sharedWithMe)
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSearchActive) {
|
||||
fetchAllProjects();
|
||||
}
|
||||
}, [isSearchActive]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeFolder === "shared") {
|
||||
sharedProject()
|
||||
}
|
||||
}, [activeFolder])
|
||||
|
||||
|
||||
return (
|
||||
<div className="dashboard-home-container">
|
||||
<DashboardNavBar
|
||||
@@ -155,7 +185,7 @@ const DashboardProjects: React.FC = () => {
|
||||
handleProjectsSearch={handleProjectsSearch}
|
||||
/>
|
||||
|
||||
<div className="container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="dashboard-container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header-wrapper" style={{ display: "flex", gap: "7px" }}>
|
||||
<button
|
||||
className={`header ${activeFolder === "myProjects" && "active"}`}
|
||||
@@ -170,7 +200,8 @@ const DashboardProjects: React.FC = () => {
|
||||
Shared with me
|
||||
</button>
|
||||
</div>
|
||||
<div className="cards-container">{renderProjects()}</div>
|
||||
<div className="cards-container">{activeFolder == "myProjects" ? renderProjects() : renderSharedProjects()}</div>
|
||||
|
||||
{projectDuplicateData && Object.keys(projectDuplicateData).length > 0 && (
|
||||
<ProjectSocketRes
|
||||
setIsSearchActive={setIsSearchActive}
|
||||
@@ -182,4 +213,142 @@ const DashboardProjects: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardProjects;
|
||||
export default DashboardProjects;
|
||||
|
||||
|
||||
|
||||
// const MyProjects = () => {
|
||||
// const { projectSocket } = useSocketStore();
|
||||
// const { userId, organization } = getUserData();
|
||||
|
||||
// const fetchAllProjects = async () => {
|
||||
// try {
|
||||
// const projects = await getAllProjects(userId, organization);
|
||||
// if (!projects || !projects.Projects) return;
|
||||
|
||||
// if (JSON.stringify(projects) !== JSON.stringify(workspaceProjects)) {
|
||||
// setWorkspaceProjects(projects);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error("Error fetching projects:", error);
|
||||
// }
|
||||
// };
|
||||
// const handleDeleteProject = async (projectId: any) => {
|
||||
// try {
|
||||
// // const deletedProject = await deleteProject(
|
||||
// // projectId,
|
||||
// // userId,
|
||||
// // organization
|
||||
// // );
|
||||
// // console.log('deletedProject: ', deletedProject);
|
||||
// const deleteProjects = {
|
||||
// projectId,
|
||||
// organization,
|
||||
// userId,
|
||||
// };
|
||||
|
||||
// //socket for deleting the project
|
||||
// if (projectSocket) {
|
||||
// projectSocket.emit("v1:project:delete", deleteProjects);
|
||||
// } else {
|
||||
// console.error("Socket is not connected.");
|
||||
// }
|
||||
// setWorkspaceProjects((prevDiscardedProjects: WorkspaceProjects) => {
|
||||
// if (!Array.isArray(prevDiscardedProjects?.Projects)) {
|
||||
// return prevDiscardedProjects;
|
||||
// }
|
||||
// const updatedProjectDatas = prevDiscardedProjects.Projects.filter(
|
||||
// (project) => project._id !== projectId
|
||||
// );
|
||||
// return {
|
||||
// ...prevDiscardedProjects,
|
||||
// Projects: updatedProjectDatas,
|
||||
// };
|
||||
// });
|
||||
// setIsSearchActive(false);
|
||||
// } catch (error) {
|
||||
// console.error("Error deleting project:", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handleDuplicateWorkspaceProject = async (
|
||||
// projectId: string,
|
||||
// projectName: string,
|
||||
// thumbnail: string
|
||||
// ) => {
|
||||
// // await handleDuplicateProjects({
|
||||
// // userId,
|
||||
// // organization,
|
||||
// // projectId,
|
||||
// // projectName,
|
||||
// // projectSocket,
|
||||
// // thumbnail,
|
||||
// // setWorkspaceProjects,
|
||||
// // setIsSearchActive
|
||||
// // });
|
||||
// const duplicateProjectData = {
|
||||
// userId,
|
||||
// thumbnail,
|
||||
// organization,
|
||||
// projectUuid: projectId,
|
||||
// projectName,
|
||||
// };
|
||||
// projectSocket.emit("v1:project:Duplicate", duplicateProjectData);
|
||||
// };
|
||||
|
||||
// const renderProjects = () => {
|
||||
// if (activeFolder !== "myProjects") return null;
|
||||
|
||||
// const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]];
|
||||
|
||||
// if (!projectList?.length) {
|
||||
// return <div className="empty-state">No projects found</div>;
|
||||
// }
|
||||
|
||||
// return projectList.map((project) => (
|
||||
// <DashboardCard
|
||||
// key={project._id}
|
||||
// projectName={project.projectName}
|
||||
// thumbnail={project.thumbnail}
|
||||
// projectId={project._id}
|
||||
// createdAt={project.createdAt}
|
||||
// handleDeleteProject={handleDeleteProject}
|
||||
// setIsSearchActive={setIsSearchActive}
|
||||
// handleDuplicateWorkspaceProject={handleDuplicateWorkspaceProject}
|
||||
// setProjectDuplicateData={setProjectDuplicateData}
|
||||
// />
|
||||
// ));
|
||||
// };
|
||||
|
||||
// const renderSharedProjects = () => {
|
||||
// if (activeFolder !== "shared") return null;
|
||||
|
||||
// const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]];
|
||||
|
||||
// if (!projectList?.length) {
|
||||
// return <div className="empty-state">No projects found</div>;
|
||||
// }
|
||||
|
||||
// return projectList.map((project) => (
|
||||
// <DashboardCard
|
||||
// key={project._id}
|
||||
// projectName={project.projectName}
|
||||
// thumbnail={project.thumbnail}
|
||||
// projectId={project._id}
|
||||
// createdAt={project.createdAt}
|
||||
// handleDeleteProject={handleDeleteProject}
|
||||
// setIsSearchActive={setIsSearchActive}
|
||||
// handleDuplicateWorkspaceProject={handleDuplicateWorkspaceProject}
|
||||
// setProjectDuplicateData={setProjectDuplicateData}
|
||||
// />
|
||||
// ));
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!isSearchActive) {
|
||||
// fetchAllProjects();
|
||||
// }
|
||||
// }, [isSearchActive]);
|
||||
|
||||
// return null
|
||||
// }
|
||||
@@ -83,7 +83,6 @@ const DashboardTrash: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleTrashDeleteProject = async (projectId: any) => {
|
||||
console.log('projectId: ', projectId);
|
||||
try {
|
||||
// const deletedProject = await deleteTrash(
|
||||
// organization, projectId
|
||||
@@ -147,7 +146,7 @@ const DashboardTrash: React.FC = () => {
|
||||
<div className="dashboard-home-container">
|
||||
<DashboardNavBar page="trash" handleTrashSearch={handleTrashSearch} />
|
||||
|
||||
<div className="container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="dashboard-container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header" style={{ display: "flex", gap: "7px" }}></div>
|
||||
<div className="cards-container">{renderTrashProjects()}</div>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,7 @@ const DashboardTutorial = () => {
|
||||
page="tutorial"
|
||||
/>
|
||||
|
||||
<div className="container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="dashboard-container" style={{ height: "calc(100% - 87px)" }}>
|
||||
<div className="header" style={{ display: 'flex', gap: '7px' }}></div>
|
||||
<div className="cards-container">
|
||||
{renderTrashProjects()}
|
||||
|
||||
@@ -42,7 +42,6 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
const projectId = generateProjectId();
|
||||
useSocketStore.getState().initializeSocket(email, organization, token);
|
||||
|
||||
|
||||
//API for creating new Project
|
||||
// const project = await createProject(
|
||||
// projectId,
|
||||
@@ -50,18 +49,16 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
// savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
// organization
|
||||
// );
|
||||
// console.log('Created project: ', project);
|
||||
|
||||
const addProject = {
|
||||
userId,
|
||||
thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage,
|
||||
organization: organization,
|
||||
projectUuid: projectId,
|
||||
};
|
||||
// console.log("projectSocket: ", projectSocket);
|
||||
|
||||
if (projectSocket) {
|
||||
// console.log('addProject: ', addProject);
|
||||
const handleResponse = (data: any) => {
|
||||
// console.log('Project add response:', data);
|
||||
if (data.message === "Project created successfully") {
|
||||
setLoadingProgress(1)
|
||||
navigate(`/${data.data.projectId}`);
|
||||
@@ -70,7 +67,6 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
};
|
||||
projectSocket.on("v1-project:response:add", handleResponse);
|
||||
|
||||
// console.log('addProject: ', addProject);
|
||||
projectSocket.emit("v1:project:add", addProject);
|
||||
} else {
|
||||
console.error("Socket is not connected.");
|
||||
|
||||
@@ -14,12 +14,24 @@ interface Project {
|
||||
createdAt: string;
|
||||
isViewed?: string
|
||||
}
|
||||
interface RecentProject {
|
||||
_id: string;
|
||||
projectName: string;
|
||||
thumbnail: string;
|
||||
createdBy: { _id: string, userName: string };
|
||||
projectUuid?: string;
|
||||
createdAt: string;
|
||||
isViewed?: string
|
||||
}
|
||||
|
||||
interface RecentProjectData {
|
||||
[key: string]: RecentProject[];
|
||||
}
|
||||
interface ProjectsData {
|
||||
[key: string]: Project[];
|
||||
}
|
||||
interface ProjectSocketResProps {
|
||||
setRecentProjects?: React.Dispatch<React.SetStateAction<ProjectsData>>;
|
||||
setRecentProjects?: React.Dispatch<React.SetStateAction<RecentProjectData>>;
|
||||
setWorkspaceProjects?: React.Dispatch<React.SetStateAction<ProjectsData>>;
|
||||
setIsSearchActive?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
useLoadingProgress,
|
||||
useRenameModeStore,
|
||||
useSaveVersion,
|
||||
useSelectedComment,
|
||||
useSelectedFloorItem,
|
||||
useSocketStore,
|
||||
useWidgetSubOption,
|
||||
@@ -32,13 +33,14 @@ import {
|
||||
import { useProductContext } from "../../../modules/simulation/products/productContext";
|
||||
import RegularDropDown from "../../ui/inputs/RegularDropDown";
|
||||
import RenameTooltip from "../../ui/features/RenameTooltip";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
|
||||
import Footer from "../../footer/Footer";
|
||||
import ThreadChat from "../../ui/collaboration/ThreadChat";
|
||||
|
||||
function MainScene() {
|
||||
const { setMainProduct } = useMainProduct();
|
||||
@@ -64,6 +66,7 @@ function MainScene() {
|
||||
const { versionHistory } = useVersionHistoryStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion, setSelectedVersion } = selectedVersionStore();
|
||||
const { selectedComment, commentPositionState } = useSelectedComment();
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== 'simulation') {
|
||||
@@ -73,7 +76,6 @@ function MainScene() {
|
||||
}, [activeModule])
|
||||
|
||||
useEffect(() => {
|
||||
console.log('versionHistory: ', versionHistory);
|
||||
if (versionHistory.length > 0) {
|
||||
setSelectedVersion(versionHistory[0])
|
||||
}
|
||||
@@ -186,6 +188,7 @@ function MainScene() {
|
||||
{activeModule !== "market" && !selectedUser && <Footer />}
|
||||
|
||||
<VersionSaved />
|
||||
{(commentPositionState !== null || selectedComment !== null) && <ThreadChat/>}
|
||||
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Search from "../../ui/inputs/Search";
|
||||
import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset";
|
||||
import { getCategoryAsset } from "../../../services/factoryBuilder/asset/assets/getCategoryAsset";
|
||||
import { fetchAssets } from "../../../services/marketplace/fetchAssets";
|
||||
import { useSelectedItem } from "../../../store/builder/store";
|
||||
|
||||
|
||||
@@ -5,16 +5,25 @@ import FileMenu from "../../ui/FileMenu";
|
||||
import { useToggleStore } from "../../../store/useUIToggleStore";
|
||||
import useModuleStore from "../../../store/useModuleStore";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useRestStates from "../../../hooks/useResetStates";
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const navigate = useNavigate();
|
||||
const { resetStates } = useRestStates();
|
||||
|
||||
return (
|
||||
<div className="header-container">
|
||||
<div className="header-content">
|
||||
<button className="logo-container" onClick={() => navigate("/Dashboard")} title="Back to Dashboard">
|
||||
<button
|
||||
className="logo-container"
|
||||
onClick={() => {
|
||||
resetStates();
|
||||
navigate("/Dashboard")
|
||||
}}
|
||||
title="Back to Dashboard"
|
||||
>
|
||||
<LogoIcon />
|
||||
</button>
|
||||
<div className="header-title">
|
||||
|
||||
@@ -1,217 +1,256 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Header from "./Header";
|
||||
import useModuleStore, {
|
||||
useSubModuleStore,
|
||||
useSubModuleStore,
|
||||
} from "../../../store/useModuleStore";
|
||||
import {
|
||||
AnalysisIcon,
|
||||
MechanicsIcon,
|
||||
PropertiesIcon,
|
||||
SimulationIcon,
|
||||
AnalysisIcon,
|
||||
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, {
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
useToolMode,
|
||||
useSaveVersion,
|
||||
useSelectedFloorItem,
|
||||
useToolMode,
|
||||
} from "../../../store/builder/store";
|
||||
import {
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
useSelectedEventData,
|
||||
useSelectedEventSphere,
|
||||
} from "../../../store/simulation/useSimulationStore";
|
||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
||||
import GlobalProperties from "./properties/GlobalProperties";
|
||||
import AsstePropertiies from "./properties/AssetProperties";
|
||||
import AssetProperties from "./properties/AssetProperties";
|
||||
import ZoneProperties from "./properties/ZoneProperties";
|
||||
import EventProperties from "./properties/eventProperties/EventProperties";
|
||||
import VersionHistory from "./versionHisory/VersionHistory";
|
||||
import AisleProperties from "./properties/AisleProperties";
|
||||
import WallProperties from "./properties/eventProperties/WallProperties";
|
||||
import WallProperties from "./properties/WallProperties";
|
||||
import FloorProperties from "./properties/FloorProperties";
|
||||
import SelectedWallProperties from "./properties/SelectedWallProperties";
|
||||
import SelectedFloorProperties from "./properties/SelectedFloorProperties";
|
||||
|
||||
const SideBarRight: React.FC = () => {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { toggleUIRight } = useToggleStore();
|
||||
const { toolMode } = useToolMode();
|
||||
const { subModule, setSubModule } = useSubModuleStore();
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { selectedEventData } = useSelectedEventData();
|
||||
const { selectedEventSphere } = useSelectedEventSphere();
|
||||
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
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();
|
||||
|
||||
// Reset activeList whenever activeModule changes
|
||||
useEffect(() => {
|
||||
if (activeModule !== "simulation") setSubModule("properties");
|
||||
if (activeModule === "simulation") setSubModule("simulations");
|
||||
}, [activeModule, setSubModule]);
|
||||
// Reset activeList whenever activeModule changes
|
||||
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 !== "mechanics" &&
|
||||
selectedEventData &&
|
||||
selectedEventSphere
|
||||
) {
|
||||
setSubModule("mechanics");
|
||||
} else if (!selectedEventData && !selectedEventSphere) {
|
||||
if (activeModule === "simulation") {
|
||||
setSubModule("simulations");
|
||||
}
|
||||
}
|
||||
if (activeModule !== "simulation") {
|
||||
setSubModule("properties");
|
||||
}
|
||||
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
<>
|
||||
{!isVersionSaved && (
|
||||
<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" && (
|
||||
return (
|
||||
<div
|
||||
className={`sidebar-right-wrapper ${toggleUIRight && (!isVersionSaved || activeModule !== "simulation") ? "open" : "closed"
|
||||
}`}
|
||||
>
|
||||
<Header />
|
||||
{toggleUIRight && (
|
||||
<>
|
||||
<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>
|
||||
{!isVersionSaved && (
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{viewVersionHistory && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<VersionHistory />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* process builder */}
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem &&
|
||||
!selectedFloor &&
|
||||
!selectedWall && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{(() => {
|
||||
if (toolMode === "Aisle") {
|
||||
return <AisleProperties />;
|
||||
} else if (toolMode === "Wall") {
|
||||
return <WallProperties />;
|
||||
} else if (toolMode === "Floor") {
|
||||
return <FloorProperties />;
|
||||
} else {
|
||||
return <GlobalProperties />;
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
selectedFloorItem && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<AssetProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem &&
|
||||
!selectedFloor &&
|
||||
!selectedAisle &&
|
||||
selectedWall && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<SelectedWallProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem &&
|
||||
!selectedWall &&
|
||||
!selectedAisle &&
|
||||
selectedFloor && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<SelectedFloorProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "zoneProperties" &&
|
||||
(activeModule === "builder" || activeModule === "simulation") && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<ZoneProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* simulation */}
|
||||
{!isVersionSaved &&
|
||||
!viewVersionHistory &&
|
||||
activeModule === "simulation" && (
|
||||
<>
|
||||
{subModule === "simulations" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Simulations />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "mechanics" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<EventProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "analysis" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Analysis />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* realtime visualization */}
|
||||
{activeModule === "visualization" && <Visualization />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{viewVersionHistory && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<VersionHistory />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* process builder */}
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
!selectedFloorItem && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
{(() => {
|
||||
if (toolMode === "Aisle") {
|
||||
return <AisleProperties />;
|
||||
} else if (toolMode === "Wall") {
|
||||
return <WallProperties />;
|
||||
} else {
|
||||
return <GlobalProperties />;
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!viewVersionHistory &&
|
||||
subModule === "properties" &&
|
||||
activeModule !== "visualization" &&
|
||||
selectedFloorItem && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<AsstePropertiies />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!viewVersionHistory &&
|
||||
subModule === "zoneProperties" &&
|
||||
(activeModule === "builder" || activeModule === "simulation") && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<ZoneProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* simulation */}
|
||||
{!isVersionSaved &&
|
||||
!viewVersionHistory &&
|
||||
activeModule === "simulation" && (
|
||||
<>
|
||||
{subModule === "simulations" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Simulations />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "mechanics" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<EventProperties />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{subModule === "analysis" && (
|
||||
<div className="sidebar-right-container">
|
||||
<div className="sidebar-right-content-container">
|
||||
<Analysis />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* realtime visualization */}
|
||||
{activeModule === "visualization" && <Visualization />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideBarRight;
|
||||
|
||||
@@ -5,6 +5,8 @@ import { RemoveIcon } from "../../../icons/ExportCommonIcons";
|
||||
import PositionInput from "../customInput/PositionInputs";
|
||||
import RotationInput from "../customInput/RotationInput";
|
||||
import { useSelectedFloorItem, useObjectPosition, useObjectRotation } from "../../../../store/builder/store";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { center } from "@turf/turf";
|
||||
|
||||
interface UserData {
|
||||
id: number; // Unique identifier for the user data
|
||||
@@ -18,6 +20,10 @@ const AssetProperties: React.FC = () => {
|
||||
const { selectedFloorItem } = useSelectedFloorItem();
|
||||
const { objectPosition } = useObjectPosition();
|
||||
const { objectRotation } = useObjectRotation();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { assets, setCurrentAnimation } = assetStore()
|
||||
const [hoveredIndex, setHoveredIndex] = useState<any>(null);
|
||||
const [isPlaying, setIsplaying] = useState(false);
|
||||
// Function to handle adding new user data
|
||||
const handleAddUserData = () => {
|
||||
const newUserData: UserData = {
|
||||
@@ -45,6 +51,12 @@ const AssetProperties: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const handleAnimationClick = (animation: string) => {
|
||||
if (selectedFloorItem) {
|
||||
const isPlaying = selectedFloorItem.animationState?.playing || false;
|
||||
setCurrentAnimation(selectedFloorItem.uuid, animation, !isPlaying);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="asset-properties-container">
|
||||
{/* Name */}
|
||||
@@ -96,6 +108,40 @@ const AssetProperties: React.FC = () => {
|
||||
+ Add
|
||||
</div>
|
||||
</section>
|
||||
<div style={{ display: "flex", flexDirection: "column", outline: "1px solid var(--border-color)" }}>
|
||||
{selectedFloorItem.uuid && <div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>Animations</div>}
|
||||
{assets.map((asset) => (
|
||||
<div key={asset.modelUuid} className="asset-item">
|
||||
{asset.modelUuid === selectedFloorItem.uuid &&
|
||||
asset.animations &&
|
||||
asset.animations.length > 0 &&
|
||||
asset.animations.map((animation, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{ gap: "15px", cursor: "pointer", padding: "5px" }}
|
||||
>
|
||||
<div
|
||||
onClick={() => handleAnimationClick(animation)}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
style={{
|
||||
height: "20px",
|
||||
width: "100%",
|
||||
borderRadius: "5px",
|
||||
background:
|
||||
hoveredIndex === index
|
||||
? "#7b4cd3"
|
||||
: "transparent",
|
||||
}}
|
||||
>
|
||||
{animation.charAt(0).toUpperCase() +
|
||||
animation.slice(1).toLowerCase()}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/white.png';
|
||||
import flootTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
type Material = {
|
||||
texture: string;
|
||||
textureId: string;
|
||||
textureName: string;
|
||||
};
|
||||
|
||||
const materials = [
|
||||
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||
{ texture: flootTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||
];
|
||||
|
||||
const FloorProperties = () => {
|
||||
const { floorDepth, isBeveled, topMaterial, sideMaterial, bevelStrength, setFloorDepth, setIsBeveled, setBevelStrength, setFloorMaterial } = useBuilderStore();
|
||||
|
||||
const [activeSurface, setActiveSurface] = useState<"top" | "side">("top");
|
||||
|
||||
const [selectedMaterials, setSelectedMaterials] = useState<{ top: Material | null; side: Material | null; }>({ top: null, side: null, });
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedMaterials({
|
||||
top: materials.find((mat) => mat.textureId === topMaterial) || null,
|
||||
side: materials.find((mat) => mat.textureId === sideMaterial) || null,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleDepthChange = (val: string) => {
|
||||
setFloorDepth(parseFloat(val));
|
||||
};
|
||||
|
||||
const handleIsBevelChange = (val: boolean) => {
|
||||
setIsBeveled(val);
|
||||
};
|
||||
|
||||
const handleBevelChange = (val: string) => {
|
||||
setBevelStrength(parseFloat(val));
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: Material) => {
|
||||
setSelectedMaterials((prev) => ({
|
||||
...prev,
|
||||
[activeSurface]: material,
|
||||
}));
|
||||
setFloorMaterial(material.textureId, activeSurface);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Floor</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Depth"
|
||||
value={`${floorDepth}`}
|
||||
min={0.1}
|
||||
max={10}
|
||||
step={0.1}
|
||||
onChange={handleDepthChange}
|
||||
/>
|
||||
<InputToggle
|
||||
value={isBeveled}
|
||||
label="Beveled"
|
||||
inputKey=""
|
||||
onClick={() => handleIsBevelChange(!isBeveled)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Bevel Strength"
|
||||
value={`${bevelStrength}`}
|
||||
min={1}
|
||||
max={10}
|
||||
step={1}
|
||||
onChange={handleBevelChange}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
<button
|
||||
className={`side-wrapper ${activeSurface === "top" ? "active" : ""}`}
|
||||
onClick={() => setActiveSurface("top")}
|
||||
>
|
||||
<div className="label">Top</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.top && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.top.texture}
|
||||
alt={selectedMaterials.top.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`side-wrapper ${activeSurface === "side" ? "active" : ""}`}
|
||||
onClick={() => setActiveSurface("side")}
|
||||
>
|
||||
<div className="label">Side</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side.texture}
|
||||
alt={selectedMaterials.side.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
{selectedMaterials[activeSurface] && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSurface]!.texture}
|
||||
alt={selectedMaterials[activeSurface]!.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
{materials.length === 0 ? (
|
||||
<div className="no-materials">No materials added yet.</div>
|
||||
) : (
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSurface]?.texture === material.texture;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FloorProperties;
|
||||
@@ -0,0 +1,250 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/white.png';
|
||||
import floorTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
|
||||
// import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi";
|
||||
|
||||
const SelectedFloorProperties = () => {
|
||||
const [depth, setDepth] = useState("");
|
||||
const [isBeveled, setIsBeveled] = useState(false);
|
||||
const [bevelStrength, setBevelStrength] = useState("");
|
||||
const { selectedFloor } = useBuilderStore();
|
||||
const { floorStore } = useSceneContext();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { socket } = useSocketStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectId } = useParams();
|
||||
const { getFloorById, updateFloor } = floorStore();
|
||||
|
||||
const [activeSurface, setActiveSurface] = useState<"top" | "side">("top");
|
||||
|
||||
const materials = [
|
||||
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||
{ texture: floorTexture1, textureId: "Material 1", textureName: "Grunge Concrete" }
|
||||
];
|
||||
|
||||
const floor = selectedFloor ? getFloorById(selectedFloor.userData.floorUuid) : null;
|
||||
|
||||
useEffect(() => {
|
||||
if (floor) {
|
||||
setDepth(floor.floorDepth.toString());
|
||||
setIsBeveled(floor.isBeveled);
|
||||
setBevelStrength(floor.bevelStrength.toString());
|
||||
}
|
||||
}, [floor]);
|
||||
|
||||
const handleDepthChange = (val: string) => {
|
||||
setDepth(val);
|
||||
const parsed = parseFloat(val);
|
||||
if (!isNaN(parsed) && floor) {
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { floorDepth: parsed });
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleBevelChange = (val: string) => {
|
||||
setBevelStrength(val);
|
||||
const parsed = parseFloat(val);
|
||||
if (!isNaN(parsed) && floor) {
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { bevelStrength: parsed });
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: { textureId: string; textureName: string }) => {
|
||||
if (!floor) return;
|
||||
const key = activeSurface === "top" ? "topMaterial" : "sideMaterial";
|
||||
const updatedFloor = updateFloor(floor.floorUuid, { [key]: material.textureId });
|
||||
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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (!floor) return null;
|
||||
|
||||
const selectedMaterials = {
|
||||
top: materials.find((m) => m.textureId === floor.topMaterial) ?? materials[0],
|
||||
side: materials.find((m) => m.textureId === floor.sideMaterial) ?? materials[0],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Floor</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Depth"
|
||||
value={depth}
|
||||
min={0.1}
|
||||
max={10}
|
||||
step={0.1}
|
||||
onChange={handleDepthChange}
|
||||
/>
|
||||
<InputToggle
|
||||
label="Beveled"
|
||||
inputKey="isBeveled"
|
||||
value={isBeveled}
|
||||
onClick={handleIsBeveledToggle}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Bevel Strength"
|
||||
value={bevelStrength}
|
||||
min={1}
|
||||
max={10}
|
||||
step={1}
|
||||
onChange={handleBevelChange}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
{(["top", "side"] as const).map((surface) => (
|
||||
<button
|
||||
key={surface}
|
||||
className={`side-wrapper ${activeSurface === surface ? "active" : ""}`}
|
||||
onClick={() => setActiveSurface(surface)}
|
||||
>
|
||||
<div className="label">{surface === "top" ? "Top" : "Side"}</div>
|
||||
<div className="texture-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[surface].texture}
|
||||
alt={selectedMaterials[surface].textureName}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSurface].texture}
|
||||
alt={selectedMaterials[activeSurface].textureName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSurface].textureId === material.textureId;
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedFloorProperties;
|
||||
@@ -0,0 +1,216 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
||||
import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
import { useSceneContext } from "../../../../modules/scene/sceneContext";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useSocketStore } from "../../../../store/builder/store";
|
||||
|
||||
// import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi";
|
||||
|
||||
const SelectedWallProperties = () => {
|
||||
const [height, setHeight] = useState("");
|
||||
const [thickness, setThickness] = useState("");
|
||||
const { selectedWall } = useBuilderStore();
|
||||
const { wallStore } = useSceneContext();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { socket } = useSocketStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectId } = useParams();
|
||||
const { getWallById, updateWall } = wallStore();
|
||||
|
||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||
|
||||
const materials = [
|
||||
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||
{ texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||
];
|
||||
|
||||
const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null;
|
||||
|
||||
useEffect(() => {
|
||||
if (wall) {
|
||||
setHeight(wall.wallHeight.toString());
|
||||
setThickness(wall.wallThickness.toString());
|
||||
}
|
||||
}, [wall, selectedWall]);
|
||||
|
||||
const handleHeightChange = (val: string) => {
|
||||
setHeight(val);
|
||||
const height = parseFloat(val);
|
||||
if (!isNaN(height) && wall) {
|
||||
const updatedWall = updateWall(wall.wallUuid, { wallHeight: height });
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleThicknessChange = (val: string) => {
|
||||
setThickness(val);
|
||||
const thickness = parseFloat(val);
|
||||
if (!isNaN(thickness) && wall) {
|
||||
const updatedWall = updateWall(wall.wallUuid, { wallThickness: thickness });
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 = {
|
||||
side1: materials.find((m) => m.textureId === wall.insideMaterial) ?? materials[0],
|
||||
side2: materials.find((m) => m.textureId === wall.outsideMaterial) ?? materials[0]
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={height}
|
||||
min={1}
|
||||
max={25}
|
||||
step={1}
|
||||
onChange={handleHeightChange}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={thickness}
|
||||
min={0.1}
|
||||
max={2}
|
||||
step={0.1}
|
||||
onChange={handleThicknessChange}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
{(["side1", "side2"] as const).map((side) => (
|
||||
<button
|
||||
key={side}
|
||||
className={`side-wrapper ${activeSide === side ? "active" : ""}`}
|
||||
onClick={() => setActiveSide(side)}
|
||||
>
|
||||
<div className="label">Side {side === "side1" ? 1 : 2}</div>
|
||||
<div className="texture-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[side].texture}
|
||||
alt={selectedMaterials[side].textureName}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSide].texture}
|
||||
alt={selectedMaterials[activeSide].textureName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSide].textureId === material.textureId;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectedWallProperties;
|
||||
@@ -0,0 +1,167 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
|
||||
|
||||
// Texture Imports
|
||||
|
||||
import defaultTexture from '../../../../assets/textures/floor/wall-tex.png';
|
||||
import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg';
|
||||
|
||||
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||
|
||||
// Define Material type
|
||||
type Material = {
|
||||
texture: string;
|
||||
textureId: string;
|
||||
textureName: string;
|
||||
};
|
||||
|
||||
const materials = [
|
||||
{ texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" },
|
||||
{ texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" }
|
||||
];
|
||||
|
||||
const WallProperties = () => {
|
||||
const { wallHeight, wallThickness, insideMaterial, outsideMaterial, setWallHeight, setWallThickness } = useBuilderStore();
|
||||
|
||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||
|
||||
const [selectedMaterials, setSelectedMaterials] = useState<{
|
||||
side1: Material | null;
|
||||
side2: Material | null;
|
||||
}>({
|
||||
side1: null,
|
||||
side2: null,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedMaterials({
|
||||
side1: materials.find((mat) => mat.textureId === outsideMaterial) || null,
|
||||
side2: materials.find((mat) => mat.textureId === insideMaterial) || null,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleHeightChange = (newValue: string) => {
|
||||
setWallHeight(parseFloat(newValue));
|
||||
};
|
||||
|
||||
const handleThicknessChange = (newValue: string) => {
|
||||
setWallThickness(parseFloat(newValue));
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: Material) => {
|
||||
setSelectedMaterials((prev) => ({
|
||||
...prev,
|
||||
[activeSide]: material,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<section className="wall-properties-section">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={`${wallHeight}`}
|
||||
min={1}
|
||||
max={25}
|
||||
step={1}
|
||||
onChange={(val) => handleHeightChange(val)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={`${wallThickness}`}
|
||||
min={0.1}
|
||||
max={2}
|
||||
step={0.1}
|
||||
onChange={(val) => handleThicknessChange(val)}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side1" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side1")}
|
||||
>
|
||||
<div className="label">Side 1</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side1 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side1.texture}
|
||||
alt={selectedMaterials.side1.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side2" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side2")}
|
||||
>
|
||||
<div className="label">Side 2</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side2 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side2.texture}
|
||||
alt={selectedMaterials.side2.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
{selectedMaterials[activeSide] && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSide]!.texture}
|
||||
alt={selectedMaterials[activeSide]!.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
{materials.length === 0 ? (
|
||||
<div className="no-materials">No materials added yet.</div>
|
||||
) : (
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSide]?.texture === material.texture;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WallProperties;
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
import { useVersionContext } from "../../../../modules/builder/version/versionContext";
|
||||
|
||||
const ZoneProperties: React.FC = () => {
|
||||
const { Edit, setEdit } = useEditPosition();
|
||||
@@ -20,6 +21,8 @@ const ZoneProperties: React.FC = () => {
|
||||
const { zones, setZones } = useZones();
|
||||
const { projectId } = useParams();
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
setZonePosition(selectedZone.zoneViewPortPosition);
|
||||
@@ -35,7 +38,7 @@ const ZoneProperties: React.FC = () => {
|
||||
viewPortCenter: zoneTarget,
|
||||
};
|
||||
|
||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId);
|
||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||
// console.log('response: ', response);
|
||||
if (response.message === "zone updated") {
|
||||
setEdit(false);
|
||||
@@ -57,7 +60,7 @@ const ZoneProperties: React.FC = () => {
|
||||
zoneName: newName,
|
||||
};
|
||||
// Call your API to update the zone
|
||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId);
|
||||
let response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||
if (response.message === "zone updated") {
|
||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||
setZones((prevZones: any[]) =>
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
|
||||
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
|
||||
|
||||
// Texture Imports
|
||||
import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png";
|
||||
import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg";
|
||||
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
|
||||
|
||||
// Define Material type
|
||||
type Material = {
|
||||
texture: string;
|
||||
textureName: string;
|
||||
};
|
||||
|
||||
// Default and initial materials
|
||||
const defaultMaterial: Material = {
|
||||
texture: defaultTexture,
|
||||
textureName: "Default Material",
|
||||
};
|
||||
|
||||
const initialMaterial: Material = {
|
||||
texture: wallTexture1,
|
||||
textureName: "Grunge Concrete Wall",
|
||||
};
|
||||
|
||||
const WallProperties = () => {
|
||||
const { wallHeight, wallThickness, setWallHeight, setWallThickness } = useBuilderStore();
|
||||
|
||||
const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1");
|
||||
|
||||
const [materials, setMaterials] = useState<Material[]>([
|
||||
defaultMaterial,
|
||||
initialMaterial,
|
||||
]);
|
||||
|
||||
const [selectedMaterials, setSelectedMaterials] = useState<{
|
||||
side1: Material | null;
|
||||
side2: Material | null;
|
||||
}>({
|
||||
side1: null,
|
||||
side2: null,
|
||||
});
|
||||
|
||||
// Set default material initially for both sides
|
||||
useEffect(() => {
|
||||
setSelectedMaterials({
|
||||
side1: defaultMaterial,
|
||||
side2: defaultMaterial,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleHeightChange = (newValue: string) => {
|
||||
setWallHeight(parseFloat(newValue));
|
||||
};
|
||||
|
||||
const handleThicknessChange = (newValue: string) => {
|
||||
setWallThickness(parseFloat(newValue));
|
||||
};
|
||||
|
||||
const handleAddMaterial = () => {
|
||||
const newMaterial: Material = {
|
||||
texture: defaultMaterial.texture,
|
||||
textureName: `Material ${materials.length + 1}`,
|
||||
};
|
||||
setMaterials([...materials, newMaterial]);
|
||||
};
|
||||
|
||||
const handleSelectMaterial = (material: Material) => {
|
||||
setSelectedMaterials((prev) => ({
|
||||
...prev,
|
||||
[activeSide]: material,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleRemoveMaterial = (index: number) => {
|
||||
const removedTexture = materials[index].texture;
|
||||
|
||||
const updatedMaterials = materials.filter((_, i) => i !== index);
|
||||
const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials;
|
||||
setMaterials(newMaterials);
|
||||
|
||||
setSelectedMaterials((prev) => {
|
||||
const updated = { ...prev };
|
||||
["side1", "side2"].forEach((side) => {
|
||||
if (updated[side as "side1" | "side2"]?.texture === removedTexture) {
|
||||
updated[side as "side1" | "side2"] = defaultMaterial;
|
||||
}
|
||||
});
|
||||
return updated;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wall-properties-container">
|
||||
<div className="header">Wall</div>
|
||||
<div className="wall-properties">
|
||||
<InputWithDropDown
|
||||
label="Height"
|
||||
value={`${wallHeight}`}
|
||||
onChange={(val) => handleHeightChange(val)}
|
||||
/>
|
||||
<InputWithDropDown
|
||||
label="Thickness"
|
||||
value={`${wallThickness}`}
|
||||
onChange={(val) => handleThicknessChange(val)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<div className="header-wrapper">
|
||||
<div className="header">Materials</div>
|
||||
<button className="addMaterial" onClick={handleAddMaterial}>
|
||||
<AddIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="material-preview">
|
||||
<div className="sides-wrapper">
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side1" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side1")}
|
||||
>
|
||||
<div className="label">Side 1</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side1 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side1.texture}
|
||||
alt={selectedMaterials.side1.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`side-wrapper ${activeSide === "side2" ? "active" : ""}`}
|
||||
onClick={() => setActiveSide("side2")}
|
||||
>
|
||||
<div className="label">Side 2</div>
|
||||
<div className="texture-image">
|
||||
{selectedMaterials.side2 && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials.side2.texture}
|
||||
alt={selectedMaterials.side2.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="preview">
|
||||
{selectedMaterials[activeSide] && (
|
||||
<img
|
||||
draggable={false}
|
||||
src={selectedMaterials[activeSide]!.texture}
|
||||
alt={selectedMaterials[activeSide]!.textureName}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="materials">
|
||||
{materials.length === 0 ? (
|
||||
<div className="no-materials">No materials added yet.</div>
|
||||
) : (
|
||||
<div className="material-container">
|
||||
{materials.map((material, index) => {
|
||||
const isSelected = selectedMaterials[activeSide]?.texture === material.texture;
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`material-wrapper ${isSelected ? "selectedMaterial" : ""}`}
|
||||
key={`${material.textureName}_${index}`}
|
||||
onClick={() => handleSelectMaterial(material)}
|
||||
>
|
||||
<div className="material-property">
|
||||
<div className="material-image">
|
||||
<img
|
||||
draggable={false}
|
||||
src={material.texture}
|
||||
alt={material.textureName}
|
||||
/>
|
||||
</div>
|
||||
<div className="material-name">{material.textureName}</div>
|
||||
</div>
|
||||
<button
|
||||
className="delete-material"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveMaterial(index);
|
||||
}}
|
||||
>
|
||||
<RemoveIcon />
|
||||
</button>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WallProperties;
|
||||
@@ -30,9 +30,9 @@ const VersionHistory = () => {
|
||||
|
||||
getVersionDataApi(projectId, version.versionId).then((verdionData) => {
|
||||
setSelectedVersion(version);
|
||||
console.log(verdionData);
|
||||
// console.log(verdionData);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
// console.log(err);
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getWidgetInputData } from "../../../../../services/visulization/zone/getWidgetInputData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -43,11 +44,11 @@ const BarChartInput = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.log("Failed to fetch zone data");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -56,33 +57,15 @@ const BarChartInput = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
let response = await getWidgetInputData(selectedChartId.id, selectedZone.zoneUuid, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchSavedInputes();
|
||||
}, [selectedChartId]);
|
||||
|
||||
@@ -108,57 +91,17 @@ const BarChartInput = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
// }
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId);
|
||||
|
||||
|
||||
if(response.message==="Widget updated successfully"){
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
}else{
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
};
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -190,7 +133,7 @@ const BarChartInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -10,6 +10,8 @@ import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getFloatingWidgetInput } from "../../../../../services/visulization/zone/getFloatingWidgetInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -27,7 +29,8 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
|
||||
const isSelected = () => { };
|
||||
@@ -38,15 +41,15 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
setLoading(true);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -55,30 +58,15 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
console.error("There was an error!", error);
|
||||
let response = await getFloatingWidgetInput(selectedChartId.id, organization,projectId,selectedVersion?.versionId||"")
|
||||
|
||||
if (response) {
|
||||
|
||||
setSelections(response.Data.Datastructure.measurements);
|
||||
setDuration(response.Data.Datastructure.duration);
|
||||
setWidgetName(response.Data.header);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,43 +93,17 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId)
|
||||
// console.log('response: ', response);
|
||||
|
||||
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
|
||||
// } as any
|
||||
// );
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// console.log("Unexpected response:", response);
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -156,7 +118,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -173,7 +135,7 @@ const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -10,6 +10,8 @@ import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getFloatingWidgetInput } from "../../../../../services/visulization/zone/getFloatingWidgetInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -28,6 +30,8 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams()
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -35,16 +39,16 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -53,30 +57,14 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
console.error("There was an error!", error);
|
||||
let response = await getFloatingWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Data.Datastructure.measurements);
|
||||
setDuration(response.Data.Datastructure.duration);
|
||||
setWidgetName(response.Data.header);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,42 +92,16 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
},
|
||||
}
|
||||
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId)
|
||||
// console.log('response: ', response);
|
||||
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// console.log("Unexpected response:", response);
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -154,7 +116,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -171,7 +133,7 @@ const FlotingWidgetInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -128,6 +128,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getWidgetInputData } from "../../../../../services/visulization/zone/getWidgetInputData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -159,11 +160,11 @@ const LineGrapInput = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -172,30 +173,14 @@ const LineGrapInput = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
let response = await getWidgetInputData(selectedChartId.id, selectedZone.zoneUuid, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -224,56 +209,18 @@ const LineGrapInput = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -305,7 +252,7 @@ const LineGrapInput = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getWidgetInputData } from "../../../../../services/visulization/zone/getWidgetInputData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -56,30 +57,14 @@ const PieChartInput = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
let response = await getWidgetInputData(selectedChartId.id, selectedZone.zoneUuid, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,17 +94,9 @@ const PieChartInput = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
@@ -129,37 +106,7 @@ const PieChartInput = (props: Props) => {
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getWidgetInputData } from "../../../../../services/visulization/zone/getWidgetInputData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -56,30 +57,14 @@ const Progress1Input = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
let response = await getWidgetInputData(selectedChartId.id, selectedZone.zoneUuid, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,16 +93,8 @@ const Progress1Input = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId);
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
@@ -127,37 +104,7 @@ const Progress1Input = (props: Props) => {
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useSocketStore } from "../../../../../store/builder/store";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingWidgets } from "../../../../../services/visulization/zone/addWidgets";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getWidgetInputData } from "../../../../../services/visulization/zone/getWidgetInputData";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -43,11 +44,11 @@ const Progress2Input = (props: Props) => {
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -56,30 +57,14 @@ const Progress2Input = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}&versionId=${selectedVersion?.versionId || ""}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
|
||||
setSelections(response.data.Datastructure.measurements);
|
||||
setDuration(response.data.Datastructure.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
|
||||
let response = await getWidgetInputData(selectedChartId.id, selectedZone.zoneUuid, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,58 +93,18 @@ const Progress2Input = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
}
|
||||
}
|
||||
|
||||
// const adding3dWidget = {
|
||||
// organization: organization,
|
||||
// widget: newWidget,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// projectId, userId
|
||||
// };
|
||||
// if (visualizationSocket) {
|
||||
// visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget);
|
||||
// }
|
||||
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId);
|
||||
|
||||
if(response.message==="Widget updated successfully"){
|
||||
let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "");
|
||||
|
||||
if (response.message === "Widget updated successfully") {
|
||||
|
||||
return true;
|
||||
}else{
|
||||
} else {
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// organization: organization,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// panel: selectedChartId.panel,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
|
||||
@@ -10,6 +10,8 @@ import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { addingFloatingWidgets } from "../../../../../services/visulization/zone/addFloatingWidgets";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { getFloatingWidgetInput } from "../../../../../services/visulization/zone/getFloatingWidgetInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -28,6 +30,8 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { projectId } = useParams();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -35,15 +39,15 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -52,29 +56,14 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer <access_token>",
|
||||
"Content-Type": "application/json",
|
||||
token: localStorage.getItem("token") || "",
|
||||
refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.header);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
let response = await getFloatingWidgetInput(selectedChartId.id, organization,projectId,selectedVersion?.versionId||"")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Data.Datastructure.measurements);
|
||||
setDuration(response.Data.Datastructure.duration);
|
||||
setWidgetName(response.Data.header);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -102,36 +91,16 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget,projectId)
|
||||
// console.log('response: ', response);
|
||||
|
||||
const response = await addingFloatingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
//
|
||||
if (response.message === "Widget updated successfully") {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
return false;
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`,
|
||||
// {
|
||||
// organization: organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// header: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// } as any
|
||||
// );
|
||||
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
// console.error("There was an error!", error);
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -146,7 +115,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -163,7 +132,7 @@ const WarehouseThroughputInputComponent = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
// console.log("name change requested", name);
|
||||
//
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -8,6 +8,10 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { adding3dWidgets } from "../../../../../services/visulization/zone/add3dWidget";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -24,6 +28,9 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -31,15 +38,15 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -48,21 +55,14 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,33 +81,61 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any,
|
||||
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -122,7 +150,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -139,7 +167,7 @@ const Widget2InputCard3D = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
//
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -8,6 +8,10 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { adding3dWidgets } from "../../../../../services/visulization/zone/add3dWidget";
|
||||
|
||||
const Widget3InputCard3D = () => {
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
@@ -22,6 +26,9 @@ const Widget3InputCard3D = () => {
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -29,15 +36,15 @@ const Widget3InputCard3D = () => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -46,21 +53,14 @@ const Widget3InputCard3D = () => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,33 +78,62 @@ const Widget3InputCard3D = () => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -119,7 +148,7 @@ const Widget3InputCard3D = () => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -132,7 +161,7 @@ const Widget3InputCard3D = () => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
//
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -8,6 +8,10 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput";
|
||||
import { useVersionContext } from "../../../../../modules/builder/version/versionContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { adding3dWidgets } from "../../../../../services/visulization/zone/add3dWidget";
|
||||
|
||||
type Props = {};
|
||||
|
||||
@@ -24,6 +28,9 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const { userName, userId, organization, email } = getUserData();
|
||||
const [isLoading, setLoading] = useState<boolean>(true);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
@@ -31,15 +38,15 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(`http://${iotApiUrl}/floatinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
//
|
||||
setDropDownData(response.data);
|
||||
setLoading(false);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
//
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch zone data");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
@@ -48,21 +55,17 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setWidgetName(response.data.widgetName);
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to fetch saved inputs");
|
||||
console.error("There was an error!", error);
|
||||
|
||||
|
||||
|
||||
let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response) {
|
||||
setSelections(response.Datastructure.measurements);
|
||||
setDuration(response.Datastructure.duration);
|
||||
setWidgetName(response.widgetName);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,33 +84,61 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
inputDuration: any,
|
||||
inputName: any
|
||||
) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
{
|
||||
organization,
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
},
|
||||
} as any
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return true;
|
||||
} else {
|
||||
// console.log("Unexpected response:", response);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to send input");
|
||||
console.error("There was an error!", error);
|
||||
return false;
|
||||
let newWidget = {
|
||||
id: selectedChartId.id,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration,
|
||||
},
|
||||
}
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "")
|
||||
|
||||
if (response.message === "widget update successfully") {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
//
|
||||
// try {
|
||||
// const response = await axios.post(
|
||||
// `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`,
|
||||
// {
|
||||
// headers: {
|
||||
// Authorization: "Bearer <access_token>",
|
||||
// "Content-Type": "application/json",
|
||||
// token: localStorage.getItem("token") || "",
|
||||
// refresh_token: localStorage.getItem("refreshToken") || "",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// organization,
|
||||
// zoneUuid: selectedZone.zoneUuid,
|
||||
// widget: {
|
||||
// id: selectedChartId.id,
|
||||
// widgetName: inputName,
|
||||
// Data: {
|
||||
// measurements: inputMeasurement,
|
||||
// duration: inputDuration,
|
||||
// },
|
||||
// },
|
||||
// projectId: projectId,
|
||||
// versionId: selectedVersion?.versionId || ""
|
||||
// } as any
|
||||
// );
|
||||
//
|
||||
// if (response.status === 200) {
|
||||
// return true;
|
||||
// } else {
|
||||
// //
|
||||
// return false;
|
||||
// }
|
||||
// } catch (error) {
|
||||
// echo.error("Failed to send input");
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSelect = async (
|
||||
@@ -122,7 +153,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
// console.log(newSelections);
|
||||
//
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
@@ -139,7 +170,7 @@ const Widget4InputCard3D = (props: Props) => {
|
||||
};
|
||||
|
||||
const handleNameChange = async (name: any) => {
|
||||
console.log("name change requested", name);
|
||||
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
|
||||
@@ -7,15 +7,23 @@ import { access } from "fs";
|
||||
import MultiEmailInvite from "../ui/inputs/MultiEmailInvite";
|
||||
import { useActiveUsers } from "../../store/builder/store";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { getProjectSharedList } from "../../services/factoryBuilder/collab/getProjectSharedList";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { projection } from "@turf/turf";
|
||||
import { shareAccess } from "../../services/factoryBuilder/collab/shareAccess";
|
||||
import { getAvatarColor } from "../../modules/collaboration/functions/getAvatarColor";
|
||||
|
||||
interface UserListTemplateProps {
|
||||
user: User;
|
||||
}
|
||||
|
||||
const UserListTemplate: React.FC<UserListTemplateProps> = ({ user }) => {
|
||||
const [accessSelection, setAccessSelection] = useState<string>(user.access);
|
||||
const [accessSelection, setAccessSelection] = useState<string>(user?.Access);
|
||||
const { projectId } = useParams();
|
||||
|
||||
function accessUpdate({ option }: AccessOption) {
|
||||
const accessUpdate = async ({ option }: AccessOption) => {
|
||||
if (!projectId) return
|
||||
const accessSelection = await shareAccess(projectId, user.userId, option)
|
||||
setAccessSelection(option);
|
||||
}
|
||||
|
||||
@@ -26,18 +34,22 @@ const UserListTemplate: React.FC<UserListTemplateProps> = ({ user }) => {
|
||||
{user.profileImage ? (
|
||||
<img
|
||||
src={user.profileImage || "https://via.placeholder.com/150"}
|
||||
alt={`${user.name}'s profile`}
|
||||
alt={`${user.
|
||||
userName}'s profile`}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="no-profile-container"
|
||||
style={{ background: user.color }}
|
||||
style={{ background: getAvatarColor(1, user.userId) }}
|
||||
>
|
||||
{user.name[0]}
|
||||
{user.
|
||||
userName.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="user-name">{user.name}</div>
|
||||
<div className="user-name"> {user.
|
||||
userName.charAt(0).toUpperCase() + user.
|
||||
userName.slice(1).toLowerCase()}</div>
|
||||
</div>
|
||||
<div className="user-access">
|
||||
<RegularDropDown
|
||||
@@ -61,39 +73,27 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
}) => {
|
||||
const { activeUsers } = useActiveUsers();
|
||||
const { userName } = getUserData();
|
||||
const [users, setUsers] = useState([])
|
||||
const { projectId } = useParams();
|
||||
|
||||
function getData() {
|
||||
if (!projectId) return;
|
||||
getProjectSharedList(projectId).then((allUser) => {
|
||||
const accesMail = allUser?.datas || []
|
||||
console.log('accesMail: ', accesMail);
|
||||
setUsers(accesMail)
|
||||
}).catch((err) => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// console.log("activeUsers: ", activeUsers);
|
||||
getData();
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
//
|
||||
}, [activeUsers]);
|
||||
const users = [
|
||||
{
|
||||
name: "Alice Johnson",
|
||||
email: "alice.johnson@example.com",
|
||||
profileImage: "",
|
||||
color: "#FF6600",
|
||||
access: "Admin",
|
||||
},
|
||||
{
|
||||
name: "Bob Smith",
|
||||
email: "bob.smith@example.com",
|
||||
profileImage: "",
|
||||
color: "#488EF6",
|
||||
access: "Viewer",
|
||||
},
|
||||
{
|
||||
name: "Charlie Brown",
|
||||
email: "charlie.brown@example.com",
|
||||
profileImage: "",
|
||||
color: "#48AC2A",
|
||||
access: "Viewer",
|
||||
},
|
||||
{
|
||||
name: "Diana Prince",
|
||||
email: "diana.prince@example.com",
|
||||
profileImage: "",
|
||||
color: "#D44242",
|
||||
access: "Viewer",
|
||||
},
|
||||
];
|
||||
return (
|
||||
<RenderOverlay>
|
||||
<div
|
||||
@@ -112,7 +112,7 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
<div className="header">
|
||||
<div className="content">Share this file</div>
|
||||
<div className="content">
|
||||
<div className="copy-link-button">copy link</div>
|
||||
{/* <div className="copy-link-button">copy link</div> */}
|
||||
<div
|
||||
className="close-button"
|
||||
onClick={() => {
|
||||
@@ -124,7 +124,7 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="invite-input-container">
|
||||
<MultiEmailInvite />
|
||||
<MultiEmailInvite users={users} getData={getData} />
|
||||
</div>
|
||||
<div className="split"></div>
|
||||
<section>
|
||||
@@ -142,7 +142,7 @@ const CollaborationPopup: React.FC<CollaborateProps> = ({
|
||||
<div className="you-container">
|
||||
<div className="your-name">
|
||||
<div className="user-profile">{userName && userName[0].toUpperCase()}</div>
|
||||
{userName}
|
||||
{userName && userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase()}
|
||||
</div>
|
||||
<div className="indicater">you</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,8 @@ import { useProjectName } from "../../store/builder/store";
|
||||
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||
import { useComparisonProduct } from "../../store/simulation/useSimulationStore";
|
||||
import { getUserData } from "../../functions/getUserData";
|
||||
import { recentlyViewed } from "../../services/dashboard/recentlyViewed";
|
||||
import { sharedWithMeProjects } from "../../services/dashboard/sharedWithMeProject";
|
||||
|
||||
interface LoadingPageProps {
|
||||
progress: number; // Expect progress as a percentage (0-100)
|
||||
@@ -19,17 +21,51 @@ const LoadingPage: React.FC<LoadingPageProps> = ({ progress }) => {
|
||||
|
||||
const validatedProgress = Math.min(100, Math.max(0, progress));
|
||||
|
||||
useEffect(() => {
|
||||
if (!userId) return;
|
||||
// useEffect(() => {
|
||||
// if (!userId) return;
|
||||
|
||||
getAllProjects(userId, organization).then((projects) => {
|
||||
const filterProject = projects?.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId);
|
||||
if (filterProject) {
|
||||
setProjectName(filterProject.projectName);
|
||||
|
||||
// // getAllProjects(userId, organization).then((projects) => {
|
||||
// // sharedWithMeProjects().then((shared) => {
|
||||
// // console.log('filterProject: ', shared);
|
||||
// // const filterProject = (projects?.Projects || shared)?.find((val: any) => val.projectUuid === projectId || val._id === projectId)
|
||||
// // console.log('filterProject: ', filterProject);
|
||||
// // // setProjectName(filterProject?.projectName)
|
||||
|
||||
// // })
|
||||
// // }).catch(() => {
|
||||
// // console.error("Error fetching projects")
|
||||
// // })
|
||||
// }, []);
|
||||
useEffect(() => {
|
||||
if (!userId) {
|
||||
console.error("User data not found in localStorage");
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchProjects = async () => {
|
||||
try {
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
const shared = await sharedWithMeProjects();
|
||||
|
||||
const allProjects = [...(projects?.Projects || []), ...(shared || [])];
|
||||
|
||||
const matchedProject = allProjects.find(
|
||||
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||
);
|
||||
|
||||
if (matchedProject) {
|
||||
setProjectName(matchedProject.projectName);
|
||||
|
||||
} else {
|
||||
console.warn("Project not found with given ID:", projectId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching projects:", error);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
};
|
||||
|
||||
fetchProjects();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -51,6 +51,7 @@ const FileMenu: React.FC = () => {
|
||||
if (!email || !userId) return;
|
||||
|
||||
const projects = await getAllProjects(userId, organization);
|
||||
if (!projects || !projects.Projects) return;
|
||||
// console.log('projects: ', projects);
|
||||
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useCommentStore } from "../../../store/collaboration/useCommentStore";
|
||||
import { useSelectedComment, useSocketStore } from "../../../store/builder/store";
|
||||
import { getRelativeTime } from "./function/getRelativeTime";
|
||||
import { editThreadTitleApi } from "../../../services/factoryBuilder/comments/editThreadTitleApi";
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
|
||||
|
||||
interface MessageProps {
|
||||
@@ -34,8 +35,9 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
const { threadSocket } = useSocketStore();
|
||||
const { userName, userId, organization } = getUserData();
|
||||
const [isEditComment, setIsEditComment] = useState(false)
|
||||
|
||||
const { selectedComment, setCommentPositionState } = useSelectedComment();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
// input
|
||||
const [value, setValue] = useState<string>(
|
||||
@@ -59,11 +61,11 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
|
||||
const handleSaveAction = async () => {
|
||||
|
||||
if (!projectId) return
|
||||
if (!projectId || !selectedVersion) return
|
||||
|
||||
if (isEditableThread && editedThread) {
|
||||
try {
|
||||
// const editThreadTitle = await editThreadTitleApi(projectId, (val as CommentSchema).threadId, value)
|
||||
// const editThreadTitle = await editThreadTitleApi(projectId, (val as CommentSchema).threadId, value, selectedVersion?.versionId || "")
|
||||
// if (editThreadTitle.message == "ThreadTitle updated Successfully") {
|
||||
// const editedThread: CommentSchema = {
|
||||
// state: 'active',
|
||||
@@ -74,7 +76,7 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
// lastUpdatedAt: new Date().toISOString(),
|
||||
// position: editThreadTitle.data.position,
|
||||
// rotation: [0, 0, 0],
|
||||
// comments: []
|
||||
// comments: [],
|
||||
// }
|
||||
// updateComment((val as CommentSchema).threadId, editedThread)
|
||||
// }
|
||||
@@ -84,17 +86,17 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
userId,
|
||||
threadTitle: value,
|
||||
organization,
|
||||
threadId: (val as CommentSchema).threadId
|
||||
threadId: (val as CommentSchema).threadId || selectedComment.threadId,
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
|
||||
threadSocket.emit('v1:thread:updateTitle', threadEdit)
|
||||
} catch {
|
||||
}
|
||||
} else {
|
||||
|
||||
if (mode === "edit") {
|
||||
try {
|
||||
// const editComments = await addCommentsApi(projectId, value, selectedComment?.threadId, (val as Reply).replyId)
|
||||
// const editComments = await addCommentsApi(projectId, value, selectedComment?.threadId, (val as Reply).replyId, selectedVersion?.versionId || "")
|
||||
//
|
||||
// const commentData = {
|
||||
// replyId: `${editComments.data?.replyId}`,
|
||||
@@ -114,7 +116,8 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
comment: value,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId,
|
||||
commentId: (val as Reply).replyId ?? ""
|
||||
commentId: (val as Reply).replyId ?? "",
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
|
||||
|
||||
@@ -133,10 +136,10 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
}
|
||||
|
||||
const handleDeleteAction = async (replyID: any) => {
|
||||
if (!projectId) return
|
||||
if (!projectId || !selectedVersion) return
|
||||
setOpenOptions(false);
|
||||
try {
|
||||
// const deletedComment = await deleteCommentApi(projectId, selectedComment?.threadId, (val as Reply).replyId)
|
||||
// const deletedComment = await deleteCommentApi(projectId, selectedComment?.threadId, (val as Reply).replyId , selectedVersion?.versionId || "")
|
||||
//
|
||||
// if (deletedComment === "'Thread comment deleted Successfully'") {
|
||||
// setMessages && setMessages(prev => prev.filter(message => message.replyId !== replyID));
|
||||
@@ -151,13 +154,16 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
userId,
|
||||
commentId: (val as Reply).replyId,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
threadId: selectedComment?.threadId,
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
|
||||
|
||||
setMessages(prev => prev.filter(message => message.replyId !== (val as Reply).replyId))
|
||||
|
||||
setMessages(prev => {
|
||||
// 👈 logs the current state
|
||||
return prev.filter(message => message.replyId !== (val as Reply).replyId);
|
||||
});
|
||||
removeReply(selectedComment?.threadId, (val as Reply).replyId); // Remove listener after response
|
||||
|
||||
|
||||
threadSocket.emit("v1-Comment:delete", deleteComment);
|
||||
}
|
||||
} catch {
|
||||
@@ -173,7 +179,7 @@ const Messages: React.FC<MessageProps> = ({ val, i, setMessages, mode, setIsEdit
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{isEditComment ? (
|
||||
|
||||
@@ -12,7 +12,7 @@ import { addCommentsApi } from "../../../services/factoryBuilder/comments/addCom
|
||||
import { deleteThreadApi } from "../../../services/factoryBuilder/comments/deleteThreadApi";
|
||||
import { createThreadApi } from "../../../services/factoryBuilder/comments/createThreadApi";
|
||||
import { getRelativeTime } from "./function/getRelativeTime";
|
||||
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
|
||||
const ThreadChat: React.FC = () => {
|
||||
const { userId, organization } = getUserData();
|
||||
@@ -35,6 +35,8 @@ const ThreadChat: React.FC = () => {
|
||||
const { threadSocket } = useSocketStore();
|
||||
const modeRef = useRef<'create' | 'edit' | null>(null);
|
||||
const messagesRef = useRef<HTMLDivElement>(null);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
modeRef.current = mode;
|
||||
@@ -42,7 +44,6 @@ const ThreadChat: React.FC = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (comments.length > 0 && selectedComment) {
|
||||
|
||||
|
||||
const allMessages = comments
|
||||
.flatMap((val: any) =>
|
||||
@@ -50,20 +51,20 @@ const ThreadChat: React.FC = () => {
|
||||
)
|
||||
.map((c) => {
|
||||
return {
|
||||
replyId: c._id ?? "",
|
||||
replyId: c._id ?? c.replyId,
|
||||
creatorId: c.creatorId || c.userId,
|
||||
createdAt: c.createdAt,
|
||||
lastUpdatedAt: "1 hr ago",
|
||||
comment: c.comment,
|
||||
_id: c._id ?? "",
|
||||
_id: c._id ?? c.replyId,
|
||||
};
|
||||
});
|
||||
|
||||
setMessages(allMessages);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}, [selectedComment])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) adjustHeight(textareaRef.current);
|
||||
@@ -145,7 +146,7 @@ const ThreadChat: React.FC = () => {
|
||||
const handleCreateComments = async (e: any) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
// const createComments = await addCommentsApi(projectId, value, selectedComment?.threadId)/
|
||||
// const createComments = await addCommentsApi(projectId, value, selectedComment?.threadId, selectedVersion?.versionId || "")/
|
||||
// if (createComments.message === 'Thread comments add Successfully' && createComments.data) {
|
||||
// const commentData = {
|
||||
// replyId: `${createComments.data?._id}`,
|
||||
@@ -164,11 +165,13 @@ const ThreadChat: React.FC = () => {
|
||||
|
||||
if (threadSocket && mode === "create") {
|
||||
const addComment = {
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
projectId,
|
||||
userId,
|
||||
comment: value,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
threadId: selectedComment?.threadId,
|
||||
|
||||
}
|
||||
|
||||
threadSocket.emit("v1-Comment:add", addComment);
|
||||
@@ -181,21 +184,22 @@ const ThreadChat: React.FC = () => {
|
||||
const handleDeleteThread = async () => {
|
||||
if (!projectId) return;
|
||||
try {
|
||||
// const deleteThread = await deleteThreadApi(projectId, selectedComment?.threadId)
|
||||
// const deleteThread = await deleteThreadApi(projectId, selectedComment?.threadId, selectedVersion?.versionId || "")
|
||||
//
|
||||
// if (deleteThread.message === "Thread deleted Successfully") {
|
||||
// removeComment(selectedComment?.threadId)
|
||||
// setSelectedComment([])
|
||||
// }
|
||||
console.log('threadSocket:threadChat ', threadSocket);
|
||||
if (threadSocket) {
|
||||
// projectId, userId, organization, threadId
|
||||
const deleteThread = {
|
||||
projectId,
|
||||
userId,
|
||||
organization,
|
||||
threadId: selectedComment?.threadId
|
||||
threadId: selectedComment?.threadId,
|
||||
versionId: selectedVersion?.versionId || ""
|
||||
}
|
||||
|
||||
setSelectedComment(null)
|
||||
removeComment(selectedComment?.threadId)
|
||||
threadSocket.emit("v1:thread:delete", deleteThread);
|
||||
@@ -213,11 +217,12 @@ const ThreadChat: React.FC = () => {
|
||||
try {
|
||||
// try {
|
||||
// const thread = await createThreadApi(
|
||||
// projectId,
|
||||
// "active",
|
||||
// commentPositionState[0].position,
|
||||
// [0, 0, 0],
|
||||
// value
|
||||
// projectId,
|
||||
// "active",
|
||||
// commentPositionState[0].position,
|
||||
// [0, 0, 0],
|
||||
// value,
|
||||
// selectedVersion?.versionId || ""
|
||||
// );
|
||||
//
|
||||
//
|
||||
@@ -243,18 +248,17 @@ const ThreadChat: React.FC = () => {
|
||||
|
||||
const createThread = {
|
||||
projectId,
|
||||
versionId: selectedVersion?.versionId || "",
|
||||
userId,
|
||||
organization,
|
||||
state: "active",
|
||||
position: commentPositionState.position,
|
||||
rotation: [0, 0, 0],
|
||||
threadTitle: value
|
||||
threadTitle: value,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
if (threadSocket) {
|
||||
console.log('createThread: ', createThread);
|
||||
|
||||
setInputActive(false);
|
||||
threadSocket.emit("v1:thread:create", createThread);
|
||||
|
||||
@@ -1,72 +1,135 @@
|
||||
import React, { useState } from "react";
|
||||
import { getSearchUsers } from "../../../services/factoryBuilder/collab/getSearchUsers";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { shareProject } from "../../../services/factoryBuilder/collab/shareProject";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
const MultiEmailInvite: React.FC = () => {
|
||||
const [emails, setEmails] = useState<string[]>([]);
|
||||
interface UserData {
|
||||
_id: string;
|
||||
Email: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
interface MultiEmailProps {
|
||||
users: any,
|
||||
getData: any,
|
||||
}
|
||||
const MultiEmailInvite: React.FC<MultiEmailProps> = ({ users, getData }) => {
|
||||
const [emails, setEmails] = useState<any>([]);
|
||||
const [searchedEmail, setSearchedEmail] = useState<UserData[]>([]);
|
||||
const [inputFocus, setInputFocus] = useState(false);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const { projectId } = useParams();
|
||||
const { userId } = getUserData();
|
||||
|
||||
const handleAddEmail = () => {
|
||||
const handleAddEmail = async (selectedUser: UserData) => {
|
||||
if (!projectId || !selectedUser) return
|
||||
const trimmedEmail = inputValue.trim();
|
||||
setEmails((prev: any[]) => {
|
||||
if (!selectedUser) return prev;
|
||||
const isNotCurrentUser = selectedUser._id !== userId;
|
||||
const alreadyExistsInEmails = prev.some(email => email._id === selectedUser._id);
|
||||
const alreadyExistsInUsers = users.some((val: any) => val.userId === selectedUser._id);
|
||||
if (isNotCurrentUser && !alreadyExistsInEmails && !alreadyExistsInUsers) {
|
||||
return [...prev, selectedUser];
|
||||
}
|
||||
|
||||
// Validate email
|
||||
if (!trimmedEmail || !validateEmail(trimmedEmail)) {
|
||||
alert("Please enter a valid email address.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for duplicates
|
||||
if (emails.includes(trimmedEmail)) {
|
||||
alert("This email has already been added.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add email to the list
|
||||
setEmails([...emails, trimmedEmail]);
|
||||
return prev;
|
||||
});
|
||||
setInputValue(""); // Clear the input field after adding
|
||||
};
|
||||
const handleSearchMail = async (e: any) => {
|
||||
setInputValue(e.target.value);
|
||||
const trimmedEmail = e.target.value.trim();
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter" || e.key === ",") {
|
||||
e.preventDefault();
|
||||
handleAddEmail();
|
||||
if (trimmedEmail.length < 3) return;
|
||||
try {
|
||||
const searchedMail = await getSearchUsers(trimmedEmail);
|
||||
const filteredEmail = searchedMail.sharchMail?.filtered;
|
||||
if (filteredEmail) {
|
||||
setSearchedEmail(filteredEmail)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to search mail:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveEmail = (emailToRemove: string) => {
|
||||
setEmails(emails.filter((email) => email !== emailToRemove));
|
||||
|
||||
const handleKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === "Enter" || e.key === "," && searchedEmail.length > 0) {
|
||||
e.preventDefault();
|
||||
handleAddEmail(searchedEmail[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveEmail = (idToRemove: string) => {
|
||||
setEmails((prev: any) => prev.filter((email: any) => email._id !== idToRemove));
|
||||
};
|
||||
|
||||
|
||||
const validateEmail = (email: string) => {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
};
|
||||
|
||||
const [inputFocus, setInputFocus] = useState(false);
|
||||
const handleInvite = () => {
|
||||
if (!projectId) return;
|
||||
try {
|
||||
emails.forEach((user: any) => {
|
||||
shareProject(user._id, projectId)
|
||||
.then((res) => {
|
||||
console.log("sharedProject:", res);
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error sharing project:", err);
|
||||
});
|
||||
setEmails([])
|
||||
setInputValue("")
|
||||
});
|
||||
setTimeout(() => {
|
||||
getData()
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.error("General error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="multi-email-invite-input-container">
|
||||
<div className={`multi-email-invite-input${inputFocus ? " active" : ""}`}>
|
||||
{emails.map((email, index) => (
|
||||
{emails.map((email: any, index: number) => (
|
||||
<div key={index} className="entered-emails">
|
||||
{email}
|
||||
<span onClick={() => handleRemoveEmail(email)}>×</span>
|
||||
{email.Email}
|
||||
<span onClick={() => handleRemoveEmail(email._id)}>×</span>
|
||||
</div>
|
||||
))}
|
||||
<input
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onChange={(e) => handleSearchMail(e)}
|
||||
onFocus={() => setInputFocus(true)}
|
||||
onBlur={() => setInputFocus(false)}
|
||||
// onBlur={() => setInputFocus(false)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Enter email and press Enter or comma to seperate"
|
||||
/>
|
||||
</div>
|
||||
<div onClick={handleAddEmail} className="invite-button">
|
||||
Invite
|
||||
</div>
|
||||
<div className="users-list-container">
|
||||
{/* list available users */}
|
||||
<div onClick={handleInvite} className="invite-button">
|
||||
Add
|
||||
</div>
|
||||
{inputFocus && inputValue.length > 2 && searchedEmail && searchedEmail.length > 0 && (
|
||||
<div className="users-list-container">
|
||||
{/* list available users here */}
|
||||
{searchedEmail.map((val: any, i: any) => (
|
||||
<div onClick={(e) => {
|
||||
handleAddEmail(val)
|
||||
setInputFocus(false)
|
||||
}} key={i} >
|
||||
{val?.Email}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,10 +17,11 @@ import {
|
||||
useZones,
|
||||
} from "../../../store/builder/store";
|
||||
import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/assest/floorAsset/setAssetsApi";
|
||||
import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
import { useSceneContext } from "../../../modules/scene/sceneContext";
|
||||
import { useVersionContext } from "../../../modules/builder/version/versionContext";
|
||||
|
||||
interface Asset {
|
||||
id: string;
|
||||
@@ -52,6 +53,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
const { assetStore } = useSceneContext();
|
||||
const { setName } = assetStore();
|
||||
const { organization } = getUserData();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
|
||||
useEffect(() => {
|
||||
useSelectedZoneStore.getState().setSelectedZone({
|
||||
@@ -81,7 +84,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
|
||||
setSubModule("zoneProperties");
|
||||
|
||||
let response = await getZoneData(id, organization, projectId);
|
||||
let response = await getZoneData(id, organization, projectId, selectedVersion?.versionId || "");
|
||||
setSelectedZone({
|
||||
zoneName: response?.zoneName,
|
||||
activeSides: response?.activeSides ?? [],
|
||||
@@ -117,7 +120,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||
zoneUuid: selectedZone.zoneUuid,
|
||||
zoneName: newName,
|
||||
};
|
||||
const response = await zoneCameraUpdate(zonesdata, organization, projectId);
|
||||
const response = await zoneCameraUpdate(zonesdata, organization, projectId, selectedVersion?.versionId || "");
|
||||
if (response.message === "zone updated") {
|
||||
setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
|
||||
setZones((prevZones: any[]) =>
|
||||
|
||||
@@ -22,7 +22,7 @@ export const getUserData = (): UserData => {
|
||||
const [_, emailDomain] = email.split("@");
|
||||
|
||||
if (!emailDomain) {
|
||||
throw new Error("Invalid email format");
|
||||
console.error("Invalid email format");
|
||||
}
|
||||
|
||||
const [organization] = emailDomain.split(".");
|
||||
|
||||
26
app/src/hooks/useResetStates.ts
Normal file
26
app/src/hooks/useResetStates.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useVersionContext } from "../modules/builder/version/versionContext";
|
||||
import { useSceneContext } from "../modules/scene/sceneContext";
|
||||
import { useProductContext } from "../modules/simulation/products/productContext";
|
||||
import { useVersionHistoryStore } from "../store/builder/useVersionHistoryStore";
|
||||
|
||||
const useRestStates = () => {
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { clearSelectedVersion } = selectedVersionStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { clearSelectedProduct } = selectedProductStore();
|
||||
const { clearVersions } = useVersionHistoryStore();
|
||||
const { clearStores } = useSceneContext();
|
||||
|
||||
const resetStates = () => {
|
||||
clearSelectedVersion();
|
||||
clearSelectedProduct();
|
||||
clearVersions();
|
||||
clearStores();
|
||||
};
|
||||
|
||||
return {
|
||||
resetStates,
|
||||
};
|
||||
};
|
||||
|
||||
export default useRestStates;
|
||||
50
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
50
app/src/modules/builder/Decal/decalInstance.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
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
|
||||
@@ -1,30 +0,0 @@
|
||||
import addLineToScene from '../../builder/geomentries/lines/addLineToScene';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function loadInitialLine(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupLine.current) return
|
||||
|
||||
////////// Load the Lines initially if there are any //////////
|
||||
|
||||
floorPlanGroupLine.current.children = [];
|
||||
lines.current.forEach((line) => {
|
||||
let colour;
|
||||
if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName) {
|
||||
colour = CONSTANTS.lineConfig.wallColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName) {
|
||||
colour = CONSTANTS.lineConfig.floorColor;
|
||||
} else if (line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName) {
|
||||
colour = CONSTANTS.lineConfig.aisleColor;
|
||||
}
|
||||
if (colour) {
|
||||
addLineToScene(line[0][0], line[1][0], colour, line, floorPlanGroupLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default loadInitialLine;
|
||||
@@ -1,87 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
////////// Load the Boxes initially if there are any //////////
|
||||
|
||||
function loadInitialPoint(
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (!floorPlanGroupPoint.current) return
|
||||
|
||||
floorPlanGroupPoint.current.children = [];
|
||||
currentLayerPoint.current = [];
|
||||
lines.current.forEach((line) => {
|
||||
const colour = getPointColor(line[0][3]);
|
||||
line.forEach((pointData) => {
|
||||
const [point, id] = pointData;
|
||||
|
||||
/////////// Check if a box with this id already exists //////////
|
||||
|
||||
const existingBox = floorPlanGroupPoint.current?.getObjectByProperty('uuid', id);
|
||||
if (existingBox) {
|
||||
return;
|
||||
}
|
||||
|
||||
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
|
||||
const material = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uOuterColor: { value: new THREE.Color(colour) }, // Blue color for the border
|
||||
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec2 vUv;
|
||||
uniform vec3 uOuterColor;
|
||||
uniform vec3 uInnerColor;
|
||||
|
||||
void main() {
|
||||
// Define the size of the white square as a proportion of the face
|
||||
float borderThickness = 0.2; // Adjust this value for border thickness
|
||||
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
|
||||
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
|
||||
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
|
||||
} else {
|
||||
gl_FragColor = vec4(uOuterColor, 1.0); // Blue border
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
const box = new THREE.Mesh(geometry, material);
|
||||
box.name = "point";
|
||||
box.uuid = id;
|
||||
box.userData = { type: line[0][3], color: colour };
|
||||
box.position.set(point.x, point.y, point.z);
|
||||
currentLayerPoint.current.push(box);
|
||||
|
||||
floorPlanGroupPoint.current?.add(box);
|
||||
});
|
||||
});
|
||||
|
||||
function getPointColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.pointConfig.wallOuterColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.pointConfig.floorOuterColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.pointConfig.aisleOuterColor;
|
||||
default: return CONSTANTS.pointConfig.defaultOuterColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (dragPointControls.current) {
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default loadInitialPoint;
|
||||
@@ -1,110 +1,110 @@
|
||||
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import * as THREE from "three";
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
// import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
// import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
// import * as THREE from "three";
|
||||
// import * as Types from "../../../types/world/worldTypes";
|
||||
// import { getWallItems } from "../../../services/factoryBuilder/asset/wallAsset/getWallItemsApi";
|
||||
// import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
||||
// import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
async function loadInitialWallItems(
|
||||
setWallItems: Types.setWallItemSetState,
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
): Promise<void> {
|
||||
if (!projectId || !versionId) return;
|
||||
try {
|
||||
const { organization, email } = getUserData();
|
||||
// async function loadInitialWallItems(
|
||||
// setWallItems: Types.setWallItemSetState,
|
||||
// projectId?: string,
|
||||
// versionId?: string
|
||||
// ): Promise<void> {
|
||||
// if (!projectId || !versionId) return;
|
||||
// try {
|
||||
// const { organization, email } = getUserData();
|
||||
|
||||
if (!email) {
|
||||
throw new Error("No email found in localStorage");
|
||||
}
|
||||
// if (!email) {
|
||||
// console.error("No email found in localStorage");
|
||||
// }
|
||||
|
||||
const items = await getWallItems(organization, projectId, versionId);
|
||||
// const items = await getWallItems(organization, projectId, versionId);
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
if (!items || items.length === 0) {
|
||||
localStorage.removeItem("WallItems");
|
||||
return;
|
||||
}
|
||||
// if (!items || items.length === 0) {
|
||||
// localStorage.removeItem("WallItems");
|
||||
// return;
|
||||
// }
|
||||
|
||||
localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
// localStorage.setItem("WallItems", JSON.stringify(items));
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
// const loader = new GLTFLoader();
|
||||
// const dracoLoader = new DRACOLoader();
|
||||
// dracoLoader.setDecoderPath(
|
||||
// "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
// );
|
||||
// loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
const loadedWallItems = await Promise.all(
|
||||
items.map(async (item: Types.WallItem) => {
|
||||
// Check THREE.js cache first
|
||||
const cachedModel = THREE.Cache.get(item.assetId!);
|
||||
if (cachedModel) {
|
||||
return processModel(cachedModel, item);
|
||||
}
|
||||
// const loadedWallItems = await Promise.all(
|
||||
// items.map(async (item: Types.WallItem) => {
|
||||
// // Check THREE.js cache first
|
||||
// const cachedModel = THREE.Cache.get(item.assetId!);
|
||||
// if (cachedModel) {
|
||||
// return processModel(cachedModel, item);
|
||||
// }
|
||||
|
||||
// Check IndexedDB cache
|
||||
const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
});
|
||||
});
|
||||
}
|
||||
// // Check IndexedDB cache
|
||||
// const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
||||
// if (cachedModelBlob) {
|
||||
// const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
// return new Promise<Types.WallItem>((resolve) => {
|
||||
// loader.load(blobUrl, (gltf) => {
|
||||
// URL.revokeObjectURL(blobUrl);
|
||||
// THREE.Cache.add(item.assetId!, gltf);
|
||||
// resolve(processModel(gltf, item));
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// Load from original URL if not cached
|
||||
const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
||||
return new Promise<Types.WallItem>((resolve) => {
|
||||
loader.load(modelUrl, async (gltf) => {
|
||||
try {
|
||||
// Cache the model
|
||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
await storeGLTF(item.assetId!, modelBlob);
|
||||
THREE.Cache.add(item.assetId!, gltf);
|
||||
resolve(processModel(gltf, item));
|
||||
} catch (error) {
|
||||
console.error("Failed to cache model:", error);
|
||||
resolve(processModel(gltf, item));
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
// // Load from original URL if not cached
|
||||
// const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
||||
// return new Promise<Types.WallItem>((resolve) => {
|
||||
// loader.load(modelUrl, async (gltf) => {
|
||||
// try {
|
||||
// // Cache the model
|
||||
// const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||
// await storeGLTF(item.assetId!, modelBlob);
|
||||
// THREE.Cache.add(item.assetId!, gltf);
|
||||
// resolve(processModel(gltf, item));
|
||||
// } catch (error) {
|
||||
// console.error("Failed to cache model:", error);
|
||||
// resolve(processModel(gltf, item));
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// })
|
||||
// );
|
||||
|
||||
setWallItems(loadedWallItems);
|
||||
} catch (error) {
|
||||
console.error("Failed to load wall items:", error);
|
||||
}
|
||||
}
|
||||
// setWallItems(loadedWallItems);
|
||||
// } catch (error) {
|
||||
// console.error("Failed to load wall items:", error);
|
||||
// }
|
||||
// }
|
||||
|
||||
function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
||||
const model = gltf.scene.clone();
|
||||
model.uuid = item.modelUuid!;
|
||||
// function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
||||
// const model = gltf.scene.clone();
|
||||
// model.uuid = item.modelUuid!;
|
||||
|
||||
model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
||||
if (child.name !== "CSG_REF") {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
// model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
||||
// if (child.name !== "CSG_REF") {
|
||||
// child.castShadow = true;
|
||||
// child.receiveShadow = true;
|
||||
// }
|
||||
// });
|
||||
|
||||
return {
|
||||
type: item.type,
|
||||
model: model,
|
||||
modelName: item.modelName,
|
||||
assetId: item.assetId,
|
||||
scale: item.scale,
|
||||
csgscale: item.csgscale,
|
||||
csgposition: item.csgposition,
|
||||
position: item.position,
|
||||
quaternion: item.quaternion,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// type: item.type,
|
||||
// model: model,
|
||||
// modelName: item.modelName,
|
||||
// assetId: item.assetId,
|
||||
// scale: item.scale,
|
||||
// csgscale: item.csgscale,
|
||||
// csgposition: item.csgposition,
|
||||
// position: item.position,
|
||||
// quaternion: item.quaternion,
|
||||
// };
|
||||
// }
|
||||
|
||||
export default loadInitialWallItems;
|
||||
// export default loadInitialWallItems;
|
||||
|
||||
@@ -48,14 +48,11 @@ function AisleInstances() {
|
||||
|
||||
{toggleView &&
|
||||
<Html
|
||||
// data
|
||||
key={`${aisle.points[0].pointUuid}_${aisle.points[1].pointUuid}`}
|
||||
userData={aisle}
|
||||
position={[textPosition.x, 1, textPosition.z]}
|
||||
// class
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
// other
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
@@ -68,7 +65,6 @@ function AisleInstances() {
|
||||
</div>
|
||||
</Html>
|
||||
}
|
||||
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -78,7 +78,7 @@ function ArcAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -65,7 +65,7 @@ function ArrowAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -68,7 +68,7 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -53,7 +53,7 @@ function CircleAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -66,7 +66,7 @@ function DashedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -53,7 +53,7 @@ function DottedAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -100,7 +100,7 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -50,7 +50,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) {
|
||||
position={[0, (aisle.points[0].layer - 1) * Constants.wallConfig.height + 0.01, 0]}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
userData={aisle}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleClick}
|
||||
onPointerMissed={() => {
|
||||
setSelectedAisle(null);
|
||||
}}
|
||||
|
||||
@@ -2,13 +2,13 @@ import * as THREE from 'three'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import ReferenceAisle from './referenceAisle';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import { createAisleApi } from '../../../../services/factoryBuilder/aisle/createAisleApi';
|
||||
import { upsertAisleApi } from '../../../../services/factoryBuilder/aisle/upsertAisleApi';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useVersionContext } from '../../version/versionContext';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import ReferenceAisle from './referenceAisle';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
|
||||
function AisleCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
@@ -74,6 +74,8 @@ function AisleCreator() {
|
||||
newPoint.layer = snappedPoint.layer;
|
||||
}
|
||||
|
||||
if (snappedPoint && snappedPoint.pointUuid === tempPoints[0]?.pointUuid) { return }
|
||||
|
||||
if (snappedPosition && !snappedPoint) {
|
||||
newPoint.position = snappedPosition;
|
||||
}
|
||||
@@ -104,7 +106,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -127,7 +129,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -149,7 +151,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -170,7 +172,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -193,7 +195,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -215,7 +217,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -236,7 +238,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
@@ -258,7 +260,7 @@ function AisleCreator() {
|
||||
};
|
||||
addAisle(aisle);
|
||||
if (projectId) {
|
||||
createAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
upsertAisleApi(aisle.aisleUuid, aisle.points, aisle.type, projectId, selectedVersion?.versionId || '')
|
||||
}
|
||||
setTempPoints([newPoint]);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ function ReferenceAisle({ tempPoints }: Readonly<ReferenceAisleProps>) {
|
||||
|
||||
useEffect(() => {
|
||||
setTempAisle(null);
|
||||
}, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor]);
|
||||
}, [toolMode, toggleView, tempPoints.length, aisleType, aisleWidth, aisleColor, activeLayer]);
|
||||
|
||||
if (!tempAisle) return null;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as THREE from "three"
|
||||
import * as THREE from "three"
|
||||
import { useEffect } from 'react'
|
||||
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||
import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi';
|
||||
import { useLoadingProgress, useRenameModeStore, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store';
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
@@ -23,10 +23,10 @@ const gltfLoaderWorker = new Worker(
|
||||
)
|
||||
);
|
||||
|
||||
function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) {
|
||||
function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
||||
const { activeModule } = useModuleStore();
|
||||
const { socket } = useSocketStore();
|
||||
const { controls, gl, pointer, camera, raycaster } = useThree();
|
||||
const { controls, gl, pointer, camera, raycaster, scene } = useThree();
|
||||
const { setLoadingProgress } = useLoadingProgress();
|
||||
const { assetStore, eventStore } = useSceneContext();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
@@ -269,7 +269,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onDrop = (event: any) => {
|
||||
const onDrop = (event: DragEvent) => {
|
||||
if (!event.dataTransfer?.files[0]) return;
|
||||
|
||||
if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') {
|
||||
@@ -277,7 +277,7 @@ function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, rea
|
||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
|
||||
addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
||||
addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,496 +3,445 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/assest/floorAsset/setAssetsApi';
|
||||
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function addAssetModel(
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
floorGroup: Types.RefGroup,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
plane: Types.RefMesh,
|
||||
selectedVersion?: Version | null,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
scene: THREE.Scene,
|
||||
raycaster: THREE.Raycaster,
|
||||
camera: THREE.Camera,
|
||||
pointer: THREE.Vector2,
|
||||
socket: Socket<any>,
|
||||
selectedItem: any,
|
||||
setSelectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
plane: Types.RefMesh,
|
||||
selectedVersion?: Version | null,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
): Promise<void> {
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
|
||||
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
|
||||
try {
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
try {
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
||||
dracoLoader.setDecoderPath(
|
||||
"https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
||||
);
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
||||
loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const floorIntersections = raycaster.intersectObjects(
|
||||
floorGroup.current.children,
|
||||
true
|
||||
);
|
||||
const intersectedFloor = floorIntersections.find((intersect) =>
|
||||
intersect.object.name.includes("Floor")
|
||||
);
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const wallFloorsGroup = scene.getObjectByName("Walls-Floors-Group") as Types.Group | null;
|
||||
const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null;
|
||||
const floorChildren = floorsGroup?.children ?? [];
|
||||
const wallFloorChildren = wallFloorsGroup?.children ?? [];
|
||||
const floorIntersections = raycaster.intersectObjects([...floorChildren, ...wallFloorChildren], true);
|
||||
const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor"));
|
||||
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
const planeIntersections = raycaster.intersectObject(plane.current!, true);
|
||||
const intersectedPlane = planeIntersections[0];
|
||||
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
let intersectPoint: THREE.Vector3 | null = null;
|
||||
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
intersectPoint =
|
||||
intersectedFloor.distance < intersectedPlane.distance
|
||||
? new THREE.Vector3(
|
||||
intersectedFloor.point.x,
|
||||
Math.round(intersectedFloor.point.y),
|
||||
intersectedFloor.point.z
|
||||
)
|
||||
: new THREE.Vector3(
|
||||
intersectedPlane.point.x,
|
||||
0,
|
||||
intersectedPlane.point.z
|
||||
);
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectedFloor.point.x,
|
||||
Math.round(intersectedFloor.point.y),
|
||||
intersectedFloor.point.z
|
||||
);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectedPlane.point.x,
|
||||
0,
|
||||
intersectedPlane.point.z
|
||||
);
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(
|
||||
intersectPoint.x,
|
||||
0,
|
||||
intersectPoint.z
|
||||
);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(
|
||||
cachedModel,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(
|
||||
gltf,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
});
|
||||
} else {
|
||||
loader.load(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(
|
||||
`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`
|
||||
).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(
|
||||
gltf,
|
||||
intersectPoint!,
|
||||
selectedItem,
|
||||
addEvent,
|
||||
addAsset,
|
||||
socket,
|
||||
selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
);
|
||||
if (intersectedFloor && intersectedPlane) {
|
||||
// intersectPoint = intersectedFloor.distance < intersectedPlane.distance ?
|
||||
// new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)
|
||||
// : new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
if (intersectedFloor.distance < intersectedPlane.distance) {
|
||||
if (intersectedFloor.object.userData.floorUuid) {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, intersectedFloor.object.userData.floorDepth, intersectedFloor.point.z);
|
||||
} else {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, 0, intersectedFloor.point.z);
|
||||
}
|
||||
} else {
|
||||
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
}
|
||||
);
|
||||
} else if (intersectedFloor) {
|
||||
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
|
||||
} else if (intersectedPlane) {
|
||||
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
|
||||
}
|
||||
}
|
||||
|
||||
if (intersectPoint) {
|
||||
|
||||
if (intersectPoint.y < 0) {
|
||||
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
|
||||
}
|
||||
const cachedModel = THREE.Cache.get(selectedItem.id);
|
||||
if (cachedModel) {
|
||||
handleModelLoad(cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||
return;
|
||||
} else {
|
||||
const cachedModelBlob = await retrieveGLTF(selectedItem.id);
|
||||
if (cachedModelBlob) {
|
||||
const blobUrl = URL.createObjectURL(cachedModelBlob);
|
||||
loader.load(blobUrl, (gltf) => {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
THREE.Cache.remove(blobUrl);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||
});
|
||||
} else {
|
||||
loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`,
|
||||
async (gltf) => {
|
||||
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob());
|
||||
await storeGLTF(selectedItem.id, modelBlob);
|
||||
THREE.Cache.add(selectedItem.id, gltf);
|
||||
await handleModelLoad(gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, selectedVersion?.versionId || '', projectId, userId);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to add asset");
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to add asset");
|
||||
} finally {
|
||||
setSelectedItem({});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleModelLoad(
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
socket: Socket<any>,
|
||||
versionId: string,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
gltf: any,
|
||||
intersectPoint: THREE.Vector3,
|
||||
selectedItem: any,
|
||||
addEvent: (event: EventsSchema) => void,
|
||||
addAsset: (asset: Asset) => void,
|
||||
socket: Socket<any>,
|
||||
versionId: string,
|
||||
projectId?: string,
|
||||
userId?: string
|
||||
) {
|
||||
const { organization } = getUserData();
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = {
|
||||
name: selectedItem.name,
|
||||
modelId: selectedItem.id,
|
||||
modelUuid: model.uuid,
|
||||
};
|
||||
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
||||
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const newFloorItem: Asset = {
|
||||
modelUuid: model.uuid,
|
||||
modelName: selectedItem.name,
|
||||
assetId: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: [0, 0, 0],
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
isCollidable: false,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
|
||||
// API
|
||||
|
||||
// await setAssetsApi(
|
||||
// organization,
|
||||
// newFloorItem.modelUuid,
|
||||
// newFloorItem.modelName,
|
||||
// newFloorItem.assetId,
|
||||
// newFloorItem.position,
|
||||
// { x: 0, y: 0, z: 0 },
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
if (selectedItem.type) {
|
||||
const data = PointsCalculator(
|
||||
selectedItem.type,
|
||||
gltf.scene.clone(),
|
||||
new THREE.Vector3(...model.rotation)
|
||||
);
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = {
|
||||
type: selectedItem.type,
|
||||
const { organization } = getUserData();
|
||||
const model = gltf.scene.clone();
|
||||
model.userData = {
|
||||
name: selectedItem.name,
|
||||
modelId: selectedItem.id,
|
||||
modelUuid: model.uuid,
|
||||
};
|
||||
model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z);
|
||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap);
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
speed: 1,
|
||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||
const triggers: TriggerSchema[] = [];
|
||||
|
||||
if (data.points && index < data.points.length - 1) {
|
||||
triggers.push({
|
||||
triggerUuid: THREE.MathUtils.generateUUID(),
|
||||
triggerName: `Trigger 1`,
|
||||
triggerType: "onComplete",
|
||||
delay: 0,
|
||||
triggeredAsset: {
|
||||
triggeredModel: {
|
||||
modelName: newFloorItem.modelName,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
},
|
||||
triggeredPoint: {
|
||||
pointName: `Point`,
|
||||
pointUuid: "",
|
||||
},
|
||||
triggeredAction: {
|
||||
actionName: `Action 1`,
|
||||
actionUuid: "",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [point.x, point.y, point.z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: "default",
|
||||
material: "Default Material",
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: triggers,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
||||
const currentPoint = ConveyorEvent.points[i];
|
||||
const nextPoint = ConveyorEvent.points[i + 1];
|
||||
|
||||
if (currentPoint.action.triggers.length > 0) {
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid =
|
||||
nextPoint.uuid;
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid =
|
||||
nextPoint.action.actionUuid;
|
||||
model.traverse((child: any) => {
|
||||
if (child) {
|
||||
child.castShadow = true;
|
||||
child.receiveShadow = true;
|
||||
}
|
||||
}
|
||||
addEvent(ConveyorEvent);
|
||||
eventData.points = ConveyorEvent.points.map((point) => ({
|
||||
uuid: point.uuid,
|
||||
position: point.position,
|
||||
rotation: point.rotation,
|
||||
}));
|
||||
} else if (selectedItem.type === "Vehicle") {
|
||||
const vehicleEvent: VehicleEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "travel",
|
||||
unLoadDuration: 5,
|
||||
loadCapacity: 1,
|
||||
steeringAngle: 0,
|
||||
pickUpPoint: null,
|
||||
unLoadPoint: null,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(vehicleEvent);
|
||||
eventData.point = {
|
||||
uuid: vehicleEvent.point.uuid,
|
||||
position: vehicleEvent.point.position,
|
||||
rotation: vehicleEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "ArmBot") {
|
||||
const roboticArmEvent: RoboticArmEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
});
|
||||
|
||||
const newFloorItem: Asset = {
|
||||
modelUuid: model.uuid,
|
||||
modelName: selectedItem.name,
|
||||
assetId: selectedItem.id,
|
||||
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
|
||||
rotation: [0, 0, 0],
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
isCollidable: false,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
|
||||
// API
|
||||
|
||||
// await setAssetsApi(
|
||||
// organization,
|
||||
// newFloorItem.modelUuid,
|
||||
// newFloorItem.modelName,
|
||||
// newFloorItem.assetId,
|
||||
// newFloorItem.position,
|
||||
// { x: 0, y: 0, z: 0 },
|
||||
// false,
|
||||
// true,
|
||||
// );
|
||||
|
||||
// SOCKET
|
||||
|
||||
if (selectedItem.type) {
|
||||
const data = PointsCalculator(
|
||||
selectedItem.type,
|
||||
gltf.scene.clone(),
|
||||
new THREE.Vector3(...model.rotation)
|
||||
);
|
||||
|
||||
if (!data || !data.points) return;
|
||||
|
||||
const eventData: any = { type: selectedItem.type, };
|
||||
|
||||
if (selectedItem.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
speed: 1,
|
||||
points: data.points.map((point: THREE.Vector3, index: number) => {
|
||||
const triggers: TriggerSchema[] = [];
|
||||
|
||||
if (data.points && index < data.points.length - 1) {
|
||||
triggers.push({
|
||||
triggerUuid: THREE.MathUtils.generateUUID(),
|
||||
triggerName: `Trigger 1`,
|
||||
triggerType: "onComplete",
|
||||
delay: 0,
|
||||
triggeredAsset: {
|
||||
triggeredModel: {
|
||||
modelName: newFloorItem.modelName,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
},
|
||||
triggeredPoint: {
|
||||
pointName: `Point`,
|
||||
pointUuid: "",
|
||||
},
|
||||
triggeredAction: {
|
||||
actionName: `Action 1`,
|
||||
actionUuid: "",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [point.x, point.y, point.z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: "default",
|
||||
material: "Default Material",
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: triggers,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
for (let i = 0; i < ConveyorEvent.points.length - 1; i++) {
|
||||
const currentPoint = ConveyorEvent.points[i];
|
||||
const nextPoint = ConveyorEvent.points[i + 1];
|
||||
|
||||
if (currentPoint.action.triggers.length > 0) {
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid;
|
||||
currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid;
|
||||
}
|
||||
}
|
||||
addEvent(ConveyorEvent);
|
||||
eventData.points = ConveyorEvent.points.map((point) => ({
|
||||
uuid: point.uuid,
|
||||
position: point.position,
|
||||
rotation: point.rotation,
|
||||
}));
|
||||
} else if (selectedItem.type === "Vehicle") {
|
||||
const vehicleEvent: VehicleEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "travel",
|
||||
unLoadDuration: 5,
|
||||
loadCapacity: 1,
|
||||
steeringAngle: 0,
|
||||
pickUpPoint: null,
|
||||
unLoadPoint: null,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(vehicleEvent);
|
||||
eventData.point = {
|
||||
uuid: vehicleEvent.point.uuid,
|
||||
position: vehicleEvent.point.position,
|
||||
rotation: vehicleEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "ArmBot") {
|
||||
const roboticArmEvent: RoboticArmEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
addEvent(roboticArmEvent);
|
||||
eventData.point = {
|
||||
uuid: roboticArmEvent.point.uuid,
|
||||
position: roboticArmEvent.point.position,
|
||||
rotation: roboticArmEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "StaticMachine") {
|
||||
const machineEvent: MachineEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "process",
|
||||
processTime: 10,
|
||||
swapMaterial: "Default Material",
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(machineEvent);
|
||||
eventData.point = {
|
||||
uuid: machineEvent.point.uuid,
|
||||
position: machineEvent.point.position,
|
||||
rotation: machineEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "Storage") {
|
||||
const storageEvent: StorageEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "store",
|
||||
storageCapacity: 10,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
eventData.point = {
|
||||
uuid: storageEvent.point.uuid,
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation,
|
||||
};
|
||||
}
|
||||
|
||||
const completeData = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
addEvent(roboticArmEvent);
|
||||
eventData.point = {
|
||||
uuid: roboticArmEvent.point.uuid,
|
||||
position: roboticArmEvent.point.position,
|
||||
rotation: roboticArmEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "StaticMachine") {
|
||||
const machineEvent: MachineEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "process",
|
||||
processTime: 10,
|
||||
swapMaterial: "Default Material",
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(machineEvent);
|
||||
eventData.point = {
|
||||
uuid: machineEvent.point.uuid,
|
||||
position: machineEvent.point.position,
|
||||
rotation: machineEvent.point.rotation,
|
||||
};
|
||||
} else if (selectedItem.type === "Storage") {
|
||||
const storageEvent: StorageEventSchema = {
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
position: newFloorItem.position,
|
||||
rotation: newFloorItem.rotation,
|
||||
state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: THREE.MathUtils.generateUUID(),
|
||||
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||
rotation: [0, 0, 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "store",
|
||||
storageCapacity: 10,
|
||||
triggers: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
eventData.point = {
|
||||
uuid: storageEvent.point.uuid,
|
||||
position: storageEvent.point.position,
|
||||
rotation: storageEvent.point.rotation,
|
||||
};
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
eventData: eventData,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
|
||||
const asset: Asset = {
|
||||
modelUuid: completeData.modelUuid,
|
||||
modelName: completeData.modelName,
|
||||
assetId: completeData.assetId,
|
||||
position: completeData.position,
|
||||
rotation: [
|
||||
completeData.rotation.x,
|
||||
completeData.rotation.y,
|
||||
completeData.rotation.z,
|
||||
] as [number, number, number],
|
||||
isLocked: completeData.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: completeData.isVisible,
|
||||
opacity: 1,
|
||||
eventData: completeData.eventData,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
} else {
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
|
||||
const asset = {
|
||||
modelUuid: data.modelUuid,
|
||||
modelName: data.modelName,
|
||||
assetId: data.assetId,
|
||||
position: data.position,
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
],
|
||||
isLocked: data.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: data.isVisible,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
}
|
||||
|
||||
const completeData = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
eventData: eventData,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", completeData);
|
||||
|
||||
const asset: Asset = {
|
||||
modelUuid: completeData.modelUuid,
|
||||
modelName: completeData.modelName,
|
||||
assetId: completeData.assetId,
|
||||
position: completeData.position,
|
||||
rotation: [
|
||||
completeData.rotation.x,
|
||||
completeData.rotation.y,
|
||||
completeData.rotation.z,
|
||||
] as [number, number, number],
|
||||
isLocked: completeData.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: completeData.isVisible,
|
||||
opacity: 1,
|
||||
eventData: completeData.eventData,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
} else {
|
||||
const data = {
|
||||
organization,
|
||||
modelUuid: newFloorItem.modelUuid,
|
||||
modelName: newFloorItem.modelName,
|
||||
assetId: newFloorItem.assetId,
|
||||
position: newFloorItem.position,
|
||||
rotation: {
|
||||
x: model.rotation.x,
|
||||
y: model.rotation.y,
|
||||
z: model.rotation.z,
|
||||
},
|
||||
isLocked: false,
|
||||
isVisible: true,
|
||||
socketId: socket.id,
|
||||
versionId: versionId,
|
||||
projectId: projectId,
|
||||
userId: userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:model-asset:add", data);
|
||||
|
||||
const asset = {
|
||||
modelUuid: data.modelUuid,
|
||||
modelName: data.modelName,
|
||||
assetId: data.assetId,
|
||||
position: data.position,
|
||||
rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [
|
||||
number,
|
||||
number,
|
||||
number
|
||||
],
|
||||
isLocked: data.isLocked,
|
||||
isCollidable: false,
|
||||
isVisible: data.isVisible,
|
||||
opacity: 1,
|
||||
};
|
||||
|
||||
addAsset(asset);
|
||||
}
|
||||
}
|
||||
|
||||
export default addAssetModel;
|
||||
|
||||
@@ -4,9 +4,9 @@ import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
|
||||
import { useActiveTool, useDeletableFloorItem, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { useActiveTool, useDeletableFloorItem, useLimitDistance, useRenderDistance, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||
import { CameraControls } from '@react-three/drei';
|
||||
import { CameraControls, Html } from '@react-three/drei';
|
||||
import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore';
|
||||
import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore';
|
||||
import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore';
|
||||
@@ -23,7 +23,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { subModule } = useSubModuleStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { assetStore, eventStore, productStore } = useSceneContext();
|
||||
const { removeAsset } = assetStore();
|
||||
const { assets, removeAsset, setAnimations } = assetStore();
|
||||
const { setTop } = useTopData();
|
||||
const { setLeft } = useLeftData();
|
||||
const { getIsEventInProduct } = productStore();
|
||||
@@ -34,6 +34,7 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { socket } = useSocketStore();
|
||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||
const { setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { limitDistance } = useLimitDistance();
|
||||
const { renderDistance } = useRenderDistance();
|
||||
const [isRendered, setIsRendered] = useState(false);
|
||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||
@@ -45,6 +46,9 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { userId, organization } = getUserData();
|
||||
const [animationNames, setAnimationNames] = useState<string[]>([]);
|
||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||
|
||||
useEffect(() => {
|
||||
setDeletableFloorItem(null);
|
||||
@@ -59,11 +63,45 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
const loadModel = async () => {
|
||||
try {
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Check Cache
|
||||
// const assetId = asset.assetId;
|
||||
// console.log('assetId: ', assetId);
|
||||
// const cachedModel = THREE.Cache.get(assetId);
|
||||
// console.log('cachedModel: ', cachedModel);
|
||||
// if (cachedModel) {
|
||||
// setGltfScene(cachedModel.scene.clone());
|
||||
// calculateBoundingBox(cachedModel.scene);
|
||||
// return;
|
||||
// }
|
||||
|
||||
const assetId = asset.assetId;
|
||||
const cachedModel = THREE.Cache.get(assetId);
|
||||
if (cachedModel) {
|
||||
setGltfScene(cachedModel.scene.clone());
|
||||
calculateBoundingBox(cachedModel.scene);
|
||||
const clonedScene = cachedModel.scene.clone();
|
||||
clonedScene.animations = cachedModel.animations || [];
|
||||
setGltfScene(clonedScene);
|
||||
calculateBoundingBox(clonedScene);
|
||||
if (cachedModel.animations && clonedScene.animations.length > 0) {
|
||||
const animationName = clonedScene.animations.map((clip: any) => clip.name);
|
||||
setAnimationNames(animationName)
|
||||
setAnimations(asset.modelUuid, animationName)
|
||||
mixerRef.current = new THREE.AnimationMixer(clonedScene);
|
||||
|
||||
clonedScene.animations.forEach((animation: any) => {
|
||||
const action = mixerRef.current!.clipAction(animation);
|
||||
actions.current[animation.name] = action;
|
||||
});
|
||||
} else {
|
||||
console.log('No animations');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,10 +163,16 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
|
||||
useFrame(() => {
|
||||
const assetPosition = new THREE.Vector3(...asset.position);
|
||||
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
||||
setIsRendered(true);
|
||||
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
||||
setIsRendered(false);
|
||||
if (limitDistance) {
|
||||
if (!isRendered && assetPosition.distanceTo(camera.position) <= renderDistance) {
|
||||
setIsRendered(true);
|
||||
} else if (isRendered && assetPosition.distanceTo(camera.position) > renderDistance) {
|
||||
setIsRendered(false);
|
||||
}
|
||||
} else {
|
||||
if (!isRendered) {
|
||||
setIsRendered(true);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -252,6 +296,32 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
clearSelectedAsset()
|
||||
}
|
||||
}
|
||||
useFrame((_, delta) => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.update(delta);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const handlePlay = (clipName: string) => {
|
||||
console.log('clipName: ', clipName, asset.animationState);
|
||||
if (!mixerRef.current) return;
|
||||
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
|
||||
const action = actions.current[clipName];
|
||||
if (action && asset.animationState?.playing) {
|
||||
action.reset().setLoop(THREE.LoopOnce, 1).play();
|
||||
console.log(`Playing: ${clipName}`);
|
||||
} else {
|
||||
console.warn(`No action found for: ${clipName}`);
|
||||
}
|
||||
};
|
||||
|
||||
handlePlay(asset.animationState?.current || '');
|
||||
|
||||
}, [asset])
|
||||
|
||||
return (
|
||||
<group
|
||||
@@ -299,7 +369,18 @@ function Model({ asset }: { readonly asset: Asset }) {
|
||||
<AssetBoundingBox boundingBox={boundingBox} />
|
||||
)
|
||||
)}
|
||||
</group>
|
||||
{/* <group >
|
||||
<Html>
|
||||
<div style={{ position: 'absolute', }}>
|
||||
{animationNames.map((name) => (
|
||||
<button key={name} onClick={() => handlePlay(name)} style={{ margin: 4 }}>
|
||||
{name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</Html>
|
||||
</group> */}
|
||||
</group >
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,137 +1,68 @@
|
||||
////////// Three and React Three Fiber Imports //////////
|
||||
|
||||
import * as THREE from "three";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useThree, useFrame } from "@react-three/fiber";
|
||||
|
||||
////////// Component Imports //////////
|
||||
|
||||
import DistanceText from "./geomentries/lines/distanceText/distanceText";
|
||||
import ReferenceDistanceText from "./geomentries/lines/distanceText/referenceDistanceText";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { Geometry } from "@react-three/csg";
|
||||
|
||||
////////// Zustand State Imports //////////
|
||||
|
||||
import {
|
||||
useToggleView,
|
||||
useActiveLayer,
|
||||
useWallVisibility,
|
||||
useRoofVisibility,
|
||||
useShadows,
|
||||
useUpdateScene,
|
||||
useWalls,
|
||||
useToolMode,
|
||||
useRefTextUpdate,
|
||||
useRenderDistance,
|
||||
useLimitDistance,
|
||||
} from "../../store/builder/store";
|
||||
|
||||
////////// 3D Function Imports //////////
|
||||
|
||||
import loadWalls from "./geomentries/walls/loadWalls";
|
||||
|
||||
import * as Types from "../../types/world/worldTypes";
|
||||
|
||||
import SocketResponses from "../collaboration/socket/socketResponses.dev";
|
||||
import FloorPlanGroup from "./groups/floorPlanGroup";
|
||||
import FloorGroup from "./groups/floorGroup";
|
||||
import Draw from "./functions/draw";
|
||||
import WallsAndWallItems from "./groups/wallsAndWallItems";
|
||||
import Ground from "../scene/environment/ground";
|
||||
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
|
||||
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
|
||||
import ZoneGroup from "./groups/zoneGroup";
|
||||
|
||||
import MeasurementTool from "../scene/tools/measurementTool";
|
||||
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
||||
import CalculateAreaGroup from "./groups/calculateAreaGroup";
|
||||
import LayoutImage from "./layout/layoutImage";
|
||||
import AssetsGroup from "./asset/assetsGroup";
|
||||
import { Bvh } from "@react-three/drei";
|
||||
import DxfFile from "./dfx/LoadBlueprint";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AislesGroup from "./aisle/aislesGroup";
|
||||
import WallGroup from "./wall/wallGroup";
|
||||
import FloorGroup from "./floor/floorGroup";
|
||||
import ZoneGroup from "./zone/zoneGroup";
|
||||
|
||||
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>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||
const csg = useRef(); // Reference for CSG object, used for 3D modeling.
|
||||
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
|
||||
const scene = useRef() as Types.RefScene; // Reference to the scene.
|
||||
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
|
||||
const state = useThree<Types.ThreeState>();
|
||||
const plane = useRef<THREE.Mesh>(null);
|
||||
const csgRef = useRef<any>(null);
|
||||
|
||||
// Assigning the scene and camera from the Three.js state to the references.
|
||||
|
||||
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
|
||||
const grid = useRef() as any; // Reference for a grid object for raycaster reference.
|
||||
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
|
||||
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
|
||||
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
|
||||
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
|
||||
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
|
||||
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
|
||||
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
|
||||
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
|
||||
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
|
||||
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
|
||||
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
|
||||
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
|
||||
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
|
||||
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
|
||||
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
|
||||
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
|
||||
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
|
||||
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
|
||||
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
|
||||
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
|
||||
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
|
||||
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
|
||||
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
|
||||
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
|
||||
|
||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
||||
|
||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
||||
const { activeLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
||||
const { toggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
||||
const { toolMode, setToolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { setToolMode } = useToolMode();
|
||||
const { setRoofVisibility } = useRoofVisibility();
|
||||
const { setWallVisibility } = useWallVisibility();
|
||||
const { setShadows } = useShadows();
|
||||
const { setRenderDistance } = useRenderDistance();
|
||||
const { setLimitDistance } = useLimitDistance();
|
||||
const { setUpdateScene } = useUpdateScene();
|
||||
const { setWalls } = useWalls();
|
||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
||||
const { projectId } = useParams();
|
||||
const { setHoveredPoint } = useBuilderStore();
|
||||
const { setHoveredPoint, setHoveredLine } = useBuilderStore();
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
// const loader = new GLTFLoader();
|
||||
// const dracoLoader = new DRACOLoader();
|
||||
|
||||
// dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||
// loader.setDRACOLoader(dracoLoader);
|
||||
|
||||
////////// All Toggle's //////////
|
||||
|
||||
useEffect(() => {
|
||||
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
|
||||
if (toggleView) {
|
||||
Layer2DVisibility(
|
||||
activeLayer,
|
||||
floorPlanGroup,
|
||||
floorPlanGroupLine,
|
||||
floorPlanGroupPoint,
|
||||
currentLayerPoint,
|
||||
dragPointControls
|
||||
);
|
||||
} else {
|
||||
if (!toggleView) {
|
||||
setHoveredLine(null);
|
||||
setHoveredPoint(null);
|
||||
state.gl.domElement.style.cursor = 'default';
|
||||
setToolMode('cursor');
|
||||
loadWalls(lines, setWalls);
|
||||
setUpdateScene(true);
|
||||
line.current = [];
|
||||
}
|
||||
}, [toggleView]);
|
||||
|
||||
@@ -150,131 +81,45 @@ export default function Builder() {
|
||||
fetchVisibility();
|
||||
}, []);
|
||||
|
||||
////////// UseFrame is Here //////////
|
||||
|
||||
useFrame(() => {
|
||||
if (toolMode) {
|
||||
Draw(
|
||||
state,
|
||||
plane,
|
||||
cursorPosition,
|
||||
floorPlanGroupPoint,
|
||||
snappedPoint,
|
||||
isSnapped,
|
||||
isSnappedUUID,
|
||||
line,
|
||||
ispreSnapped,
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
setRefTextUpdate,
|
||||
Tube,
|
||||
anglesnappedPoint,
|
||||
isAngleSnapped,
|
||||
toolMode
|
||||
);
|
||||
if (csgRef.current) {
|
||||
csgRef.current.update();
|
||||
}
|
||||
});
|
||||
|
||||
////////// Return //////////
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<Ground grid={grid} plane={plane} />
|
||||
<Ground plane={plane} />
|
||||
|
||||
<Bvh firstHitOnly>
|
||||
<DistanceText key={toggleView} />
|
||||
</Bvh>
|
||||
<SocketResponses />
|
||||
|
||||
<ReferenceDistanceText
|
||||
key={refTextupdate}
|
||||
line={ReferenceLineMesh.current}
|
||||
/>
|
||||
<AssetsGroup plane={plane} />
|
||||
|
||||
<Bvh firstHitOnly>
|
||||
<SocketResponses
|
||||
floorPlanGroup={floorPlanGroup}
|
||||
lines={lines}
|
||||
floorGroup={floorGroup}
|
||||
scene={scene}
|
||||
onlyFloorlines={onlyFloorlines}
|
||||
currentLayerPoint={currentLayerPoint}
|
||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||
floorPlanGroupLine={floorPlanGroupLine}
|
||||
dragPointControls={dragPointControls}
|
||||
/>
|
||||
</Bvh>
|
||||
<mesh name='Walls-And-WallAssets-Group'>
|
||||
<Geometry ref={csgRef} useGroups>
|
||||
|
||||
<WallsAndWallItems
|
||||
CSGGroup={CSGGroup}
|
||||
setSelectedItemsIndex={setSelectedItemsIndex}
|
||||
selectedItemsIndex={selectedItemsIndex}
|
||||
currentWallItem={currentWallItem}
|
||||
csg={csg}
|
||||
lines={lines}
|
||||
hoveredDeletableWallItem={hoveredDeletableWallItem}
|
||||
/>
|
||||
<WallGroup />
|
||||
|
||||
<Bvh firstHitOnly>
|
||||
<WallAssetGroup />
|
||||
|
||||
<FloorGroup
|
||||
floorGroup={floorGroup}
|
||||
lines={lines}
|
||||
referencePole={referencePole}
|
||||
hoveredDeletablePillar={hoveredDeletablePillar}
|
||||
/>
|
||||
</Geometry>
|
||||
</mesh>
|
||||
|
||||
<FloorPlanGroup
|
||||
floorPlanGroup={floorPlanGroup}
|
||||
floorPlanGroupLine={floorPlanGroupLine}
|
||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||
floorGroup={floorGroup}
|
||||
currentLayerPoint={currentLayerPoint}
|
||||
dragPointControls={dragPointControls}
|
||||
hoveredDeletablePoint={hoveredDeletablePoint}
|
||||
hoveredDeletableLine={hoveredDeletableLine}
|
||||
plane={plane}
|
||||
line={line}
|
||||
lines={lines}
|
||||
onlyFloorline={onlyFloorline}
|
||||
onlyFloorlines={onlyFloorlines}
|
||||
ReferenceLineMesh={ReferenceLineMesh}
|
||||
LineCreated={LineCreated}
|
||||
isSnapped={isSnapped}
|
||||
ispreSnapped={ispreSnapped}
|
||||
snappedPoint={snappedPoint}
|
||||
isSnappedUUID={isSnappedUUID}
|
||||
isAngleSnapped={isAngleSnapped}
|
||||
anglesnappedPoint={anglesnappedPoint}
|
||||
/>
|
||||
<AislesGroup />
|
||||
|
||||
<ZoneGroup />
|
||||
<FloorGroup />
|
||||
|
||||
<AssetsGroup
|
||||
floorGroup={floorGroup}
|
||||
plane={plane}
|
||||
/>
|
||||
<ZoneGroup />
|
||||
|
||||
<AislesGroup />
|
||||
<MeasurementTool />
|
||||
|
||||
<MeasurementTool />
|
||||
<CalculateAreaGroup />
|
||||
|
||||
<CalculateAreaGroup />
|
||||
<NavMesh />
|
||||
|
||||
<NavMesh lines={lines} />
|
||||
<DxfFile />
|
||||
|
||||
<DxfFile
|
||||
lines={lines}
|
||||
dragPointControls={dragPointControls}
|
||||
currentLayerPoint={currentLayerPoint}
|
||||
floorPlanGroupLine={floorPlanGroupLine}
|
||||
floorPlanGroupPoint={floorPlanGroupPoint}
|
||||
/>
|
||||
|
||||
<LayoutImage />
|
||||
</Bvh>
|
||||
|
||||
{/* <WallGroup /> */}
|
||||
<LayoutImage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store';
|
||||
import { LineBasicMaterial, Line } from 'three';
|
||||
import loadInitialPoint from '../IntialLoad/loadInitialPoint';
|
||||
import loadInitialLine from '../IntialLoad/loadInitialLine';
|
||||
import { TransformControls } from '@react-three/drei';
|
||||
import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint';
|
||||
import * as Types from '../../../types/world/worldTypes';
|
||||
import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { getUserData } from '../../../functions/getUserData';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
|
||||
// Interface defining the props for the DxfFile component
|
||||
interface DxfFileProps {
|
||||
lines: Types.RefLines; // Reference to lines in the DXF file
|
||||
floorPlanGroupPoint: Types.RefGroup; // Reference to floor plan points group
|
||||
dragPointControls: Types.RefDragControl; // Reference to drag controls
|
||||
floorPlanGroupLine: Types.RefGroup; // Reference to floor plan lines group
|
||||
currentLayerPoint: Types.RefMeshArray; // Reference to current layer points
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* transformation controls for interactive editing.
|
||||
*/
|
||||
const DxfFile = ({
|
||||
floorPlanGroupPoint,
|
||||
currentLayerPoint,
|
||||
dragPointControls,
|
||||
floorPlanGroupLine,
|
||||
lines,
|
||||
}: DxfFileProps) => {
|
||||
const DxfFile = () => {
|
||||
// State management hooks
|
||||
const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload();
|
||||
const { setUpdateScene } = useUpdateScene();
|
||||
const { toggleView } = useToggleView();
|
||||
const { socket } = useSocketStore();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
@@ -50,54 +31,34 @@ const DxfFile = ({
|
||||
* Loads initial points and lines from the DXF data and updates the scene.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (
|
||||
dfxWallGenerate &&
|
||||
dragPointControls &&
|
||||
floorPlanGroupPoint &&
|
||||
currentLayerPoint &&
|
||||
floorPlanGroupLine
|
||||
) {
|
||||
if (dfxWallGenerate) {
|
||||
// Store generated lines in ref
|
||||
lines.current.push(...dfxWallGenerate);
|
||||
dfxWallGenerate.map((line: any) => {
|
||||
const lineData = arrayLineToObject(line as Types.Line);
|
||||
// lines.current.push(...dfxWallGenerate);
|
||||
// dfxWallGenerate.map((line: any) => {
|
||||
// const lineData = arrayLineToObject(line as Types.Line);
|
||||
|
||||
//REST
|
||||
// //REST
|
||||
|
||||
// setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
|
||||
// // setLine(organization, lineData.layer!, lineData.line!, lineData.type!);
|
||||
|
||||
//SOCKET
|
||||
// //SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: lineData.layer,
|
||||
line: lineData.line,
|
||||
type: lineData.type,
|
||||
socketId: socket.id,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
projectId,
|
||||
userId
|
||||
}
|
||||
// const input = {
|
||||
// organization,
|
||||
// layer: lineData.layer,
|
||||
// line: lineData.line,
|
||||
// type: lineData.type,
|
||||
// socketId: socket.id,
|
||||
// versionId: selectedVersion?.versionId || '',
|
||||
// projectId,
|
||||
// userId
|
||||
// }
|
||||
|
||||
socket.emit('v1:Line:create', input);
|
||||
// socket.emit('v1:Line:create', input);
|
||||
|
||||
})
|
||||
|
||||
// Load initial points and lines from DXF data
|
||||
loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
|
||||
loadInitialLine(floorPlanGroupLine, lines);
|
||||
|
||||
// Trigger scene update
|
||||
setUpdateScene(true);
|
||||
// })
|
||||
}
|
||||
}, [
|
||||
lines,
|
||||
floorPlanGroupLine,
|
||||
floorPlanGroupPoint,
|
||||
currentLayerPoint,
|
||||
dragPointControls,
|
||||
dfxWallGenerate,
|
||||
]);
|
||||
}, [dfxWallGenerate]);
|
||||
|
||||
/**
|
||||
* Handles transformation changes for individual lines.
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
import { DragControls } from "three/examples/jsm/controls/DragControls";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
import DragPoint from "../geomentries/points/dragPoint";
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../functions/getUserData";
|
||||
|
||||
export default async function addDragControl(
|
||||
dragPointControls: Types.RefDragControl,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
state: Types.ThreeState,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
lines: Types.RefLines,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string
|
||||
) {
|
||||
////////// Dragging Point and also change the size to indicate during hover //////////
|
||||
|
||||
dragPointControls.current = new DragControls(
|
||||
currentLayerPoint.current,
|
||||
state.camera,
|
||||
state.gl.domElement
|
||||
);
|
||||
dragPointControls.current.enabled = false;
|
||||
const { userId, organization, email } = getUserData();
|
||||
dragPointControls.current.addEventListener("drag", function (event) {
|
||||
const object = event.object;
|
||||
if (object.visible) {
|
||||
(state.controls as any).enabled = false;
|
||||
DragPoint(
|
||||
event as any,
|
||||
floorPlanGroupPoint,
|
||||
floorPlanGroupLine,
|
||||
state.scene,
|
||||
lines,
|
||||
onlyFloorlines
|
||||
);
|
||||
} else {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener("dragstart", function (event) { });
|
||||
|
||||
dragPointControls.current.addEventListener("dragend", async function (event) {
|
||||
if (!dragPointControls.current) return;
|
||||
|
||||
//REST
|
||||
|
||||
// await updatePoint(
|
||||
// organization,
|
||||
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
|
||||
// event.object.uuid,
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
position: {
|
||||
x: event.object.position.x,
|
||||
y: 0.01,
|
||||
z: event.object.position.z,
|
||||
},
|
||||
uuid: event.object.uuid,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:update", data);
|
||||
|
||||
if (state.controls) {
|
||||
(state.controls as any).enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener("hoveron", function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(
|
||||
event.object.userData.color
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
dragPointControls.current.addEventListener("hoveroff", function (event: any) {
|
||||
if ((event.object as Types.Mesh).name === "point") {
|
||||
event.object.material.uniforms.uInnerColor.value.set(
|
||||
new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
export default function handleContextMenu(
|
||||
menuVisible: Types.Boolean,
|
||||
setMenuVisible: Types.BooleanState
|
||||
): void {
|
||||
// setMenuVisible(true)
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshDown(
|
||||
event: Types.MeshEvent,
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState,
|
||||
wallItems: Types.wallItems,
|
||||
toggleView: Types.Boolean
|
||||
): void {
|
||||
|
||||
////////// To select which of the Wall item and CSG is selected to be dragged //////////
|
||||
|
||||
if (!toggleView) {
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
|
||||
if (event.intersections.length > 0) {
|
||||
if (event.object) {
|
||||
const wallItemModel = event.object;
|
||||
let currentObject = wallItemModel as THREE.Object3D;
|
||||
while (currentObject) {
|
||||
if (currentObject.name === "Scene") {
|
||||
break;
|
||||
}
|
||||
currentObject = currentObject.parent as THREE.Object3D;
|
||||
}
|
||||
if (!currentObject) return;
|
||||
const clickedIndex = wallItems.findIndex((item) => item.model?.uuid === currentObject.uuid);
|
||||
if (clickedIndex !== -1) {
|
||||
setSelectedItemsIndex(clickedIndex);
|
||||
const wallItemModel = wallItems[clickedIndex]?.model;
|
||||
if (wallItemModel) {
|
||||
setSelectedWallItem(wallItemModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
export default handleMeshDown;
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function handleMeshMissed(
|
||||
currentWallItem: Types.RefMesh,
|
||||
setSelectedWallItem: Types.setSelectedWallItemSetState,
|
||||
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState
|
||||
): void {
|
||||
|
||||
////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null //////////
|
||||
|
||||
if (currentWallItem.current) {
|
||||
currentWallItem.current.children.forEach((child) => {
|
||||
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
|
||||
const material = (child as THREE.Mesh).material;
|
||||
|
||||
if (Array.isArray(material)) {
|
||||
material.forEach(mat => {
|
||||
if (mat instanceof THREE.MeshStandardMaterial) {
|
||||
mat.emissive = new THREE.Color("black");
|
||||
}
|
||||
});
|
||||
} else if (material instanceof THREE.MeshStandardMaterial) {
|
||||
material.emissive = new THREE.Color("black");
|
||||
}
|
||||
}
|
||||
});
|
||||
currentWallItem.current = null;
|
||||
setSelectedWallItem(null);
|
||||
setSelectedItemsIndex(null);
|
||||
}
|
||||
}
|
||||
|
||||
export default handleMeshMissed;
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useMemo } from 'react';
|
||||
import { DoubleSide, Shape, Vector2 } from 'three';
|
||||
import { Extrude } from '@react-three/drei';
|
||||
import * as Constants from '../../../../../types/world/worldConstants';
|
||||
|
||||
function Floor2DInstance({ floor }: { floor: Floor }) {
|
||||
const savedTheme: string | null = localStorage.getItem("theme");
|
||||
|
||||
const shape = useMemo(() => {
|
||||
const shape = new Shape();
|
||||
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);
|
||||
}
|
||||
return shape;
|
||||
}, [floor]);
|
||||
|
||||
if (!shape) return null;
|
||||
|
||||
return (
|
||||
<mesh
|
||||
castShadow
|
||||
receiveShadow
|
||||
name={`Floor-2D-${floor.floorUuid}`}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
position={[0, 0, 0]}
|
||||
userData={floor}
|
||||
>
|
||||
<Extrude
|
||||
name={`Floor-${floor.floorUuid}`}
|
||||
args={[shape, {
|
||||
depth: Constants.floorConfig.height,
|
||||
}]}
|
||||
userData={floor}
|
||||
>
|
||||
<meshBasicMaterial
|
||||
color={savedTheme === "dark" ? "#808080" : "#808080"}
|
||||
side={DoubleSide}
|
||||
transparent
|
||||
opacity={0.4}
|
||||
depthWrite={false}
|
||||
/>
|
||||
</Extrude>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
export default Floor2DInstance;
|
||||
@@ -0,0 +1,108 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Shape, Vector2, DoubleSide, TextureLoader, RepeatWrapping, SRGBColorSpace } 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 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';
|
||||
|
||||
function FloorInstance({ floor }: { floor: Floor }) {
|
||||
const { togglView } = useToggleView();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedFloor, setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
|
||||
const materials: Record<string, string> = {
|
||||
"Default Material": savedTheme === "dark" ? texturePathDark : texturePath,
|
||||
"Material 1": savedTheme === "dark" ? material1 : material1,
|
||||
};
|
||||
|
||||
const shape = useMemo(() => {
|
||||
const shape = new Shape();
|
||||
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);
|
||||
}
|
||||
return shape;
|
||||
}, [floor]);
|
||||
|
||||
const textureScale = Constants.floorConfig.textureScale;
|
||||
|
||||
const [topTexture, sideTexture] = useLoader(
|
||||
TextureLoader,
|
||||
[
|
||||
materials[floor.topMaterial] || materials['Default Material'],
|
||||
materials[floor.sideMaterial] || materials['Default Material']
|
||||
]
|
||||
);
|
||||
|
||||
if (!materials[floor.topMaterial] || !materials[floor.sideMaterial]) return null;
|
||||
|
||||
[topTexture, sideTexture].forEach(tex => {
|
||||
tex.wrapS = tex.wrapT = RepeatWrapping;
|
||||
tex.repeat.set(textureScale, textureScale);
|
||||
tex.colorSpace = SRGBColorSpace;
|
||||
});
|
||||
|
||||
if (!shape) return null;
|
||||
|
||||
return (
|
||||
<mesh
|
||||
castShadow
|
||||
receiveShadow
|
||||
name={`Floor-${floor.floorUuid}`}
|
||||
rotation={[Math.PI / 2, 0, 0]}
|
||||
position={[0, !floor.isBeveled ? (floor.floorDepth - 0.1) : (floor.floorDepth - 0.2), 0]}
|
||||
userData={floor}
|
||||
onDoubleClick={(e) => {
|
||||
if (!togglView && activeModule === 'builder') {
|
||||
if (e.object.userData.floorUuid) {
|
||||
e.stopPropagation();
|
||||
setSelectedFloor(e.object);
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
if (selectedFloor && selectedFloor.userData.floorUuid === floor.floorUuid) {
|
||||
setSelectedFloor(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<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}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
attach="material-0"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={topTexture}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
<meshStandardMaterial
|
||||
attach="material-1"
|
||||
color={Constants.floorConfig.defaultColor}
|
||||
map={sideTexture}
|
||||
side={DoubleSide}
|
||||
/>
|
||||
</Extrude>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorInstance;
|
||||
133
app/src/modules/builder/floor/Instances/floorInstances.tsx
Normal file
133
app/src/modules/builder/floor/Instances/floorInstances.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
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 Line from '../../line/line';
|
||||
import Point from '../../point/point';
|
||||
import FloorInstance from './Instance/floorInstance';
|
||||
import Floor2DInstance from './Instance/floor2DInstance';
|
||||
|
||||
function FloorInstances() {
|
||||
const { floorStore } = useSceneContext();
|
||||
const { floors } = floorStore();
|
||||
const { toggleView } = useToggleView();
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('floors: ', floors);
|
||||
}, [floors])
|
||||
|
||||
const allPoints = useMemo(() => {
|
||||
const points: Point[] = [];
|
||||
const seenUuids = new Set<string>();
|
||||
|
||||
floors.forEach(floor => {
|
||||
floor.points.forEach(point => {
|
||||
if (!seenUuids.has(point.pointUuid)) {
|
||||
seenUuids.add(point.pointUuid);
|
||||
points.push(point);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return points;
|
||||
}, [floors]);
|
||||
|
||||
const allLines = useMemo(() => {
|
||||
const lines: { start: Point; end: Point; key: string }[] = [];
|
||||
const seenUuids = new Set<string>();
|
||||
|
||||
floors.forEach((floor) => {
|
||||
const points = floor.points;
|
||||
if (points.length < 2) return;
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
const current = points[i];
|
||||
const next = points[(i + 1) % points.length];
|
||||
const lineKey = `${current.pointUuid}-${next.pointUuid}`;
|
||||
if (current.pointUuid !== next.pointUuid && !seenUuids.has(lineKey)) {
|
||||
seenUuids.add(lineKey);
|
||||
lines.push({
|
||||
start: current,
|
||||
end: next,
|
||||
key: lineKey
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return lines;
|
||||
}, [floors]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
{!toggleView && floors.length > 0 && (
|
||||
<mesh name='Floors-Group'>
|
||||
{floors.map((floor) => (
|
||||
<FloorInstance key={floor.floorUuid} floor={floor} />
|
||||
))}
|
||||
</mesh>
|
||||
)}
|
||||
|
||||
{toggleView && floors.length > 0 && (
|
||||
<mesh name='Floors-2D-Group'>
|
||||
{floors.map((floor) => (
|
||||
<Floor2DInstance key={floor.floorUuid} floor={floor} />
|
||||
))}
|
||||
</mesh>
|
||||
)}
|
||||
|
||||
{toggleView && (
|
||||
<>
|
||||
<group name='Floor-Points-Group'>
|
||||
{allPoints.map((point) => (
|
||||
<Point key={point.pointUuid} point={point} />
|
||||
))}
|
||||
</group>
|
||||
|
||||
<group name='Floor-Lines-Group'>
|
||||
|
||||
{allLines.map(({ start, end, key }) => (
|
||||
<Line key={key} points={[start, end]} />
|
||||
))}
|
||||
|
||||
{allLines.map((line) => {
|
||||
const { start, end, key } = line;
|
||||
const textPosition = new Vector3().addVectors(new Vector3(...start.position), new Vector3(...end.position)).divideScalar(2);
|
||||
const distance = new Vector3(...start.position).distanceTo(new Vector3(...end.position));
|
||||
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
{toggleView &&
|
||||
<Html
|
||||
key={`${start.pointUuid}_${end.pointUuid}`}
|
||||
userData={line}
|
||||
position={[textPosition.x, 1, textPosition.z]}
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
>
|
||||
<div
|
||||
key={key}
|
||||
className={`distance ${key}`}
|
||||
>
|
||||
{distance.toFixed(2)} m
|
||||
</div>
|
||||
</Html>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
</group>
|
||||
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorInstances;
|
||||
267
app/src/modules/builder/floor/floorCreator/floorCreator.tsx
Normal file
267
app/src/modules/builder/floor/floorCreator/floorCreator.tsx
Normal file
@@ -0,0 +1,267 @@
|
||||
import * as THREE from 'three'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useVersionContext } from '../../version/versionContext';
|
||||
import { getUserData } from '../../../../functions/getUserData';
|
||||
import ReferencePoint from '../../point/reference/referencePoint';
|
||||
import ReferenceFloor from './referenceFloor';
|
||||
|
||||
// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi';
|
||||
|
||||
function FloorCreator() {
|
||||
const { scene, camera, raycaster, gl, pointer } = useThree();
|
||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||
const { toggleView } = useToggleView();
|
||||
const { toolMode } = useToolMode();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { socket } = useSocketStore();
|
||||
const { floorStore } = useSceneContext();
|
||||
const { addFloor, getFloorPointById, getFloorByPoints } = floorStore();
|
||||
const drag = useRef(false);
|
||||
const isLeftMouseDown = useRef(false);
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { userId, organization } = getUserData();
|
||||
const { projectId } = useParams();
|
||||
|
||||
const [tempPoints, setTempPoints] = useState<Point[]>([]);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const { floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint, setSnappedPoint, setSnappedPosition } = useBuilderStore();
|
||||
|
||||
useEffect(() => {
|
||||
const canvasElement = gl.domElement;
|
||||
|
||||
const onMouseDown = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = true;
|
||||
drag.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseUp = (evt: any) => {
|
||||
if (evt.button === 0) {
|
||||
isLeftMouseDown.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseMove = () => {
|
||||
if (isLeftMouseDown) {
|
||||
drag.current = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseClick = () => {
|
||||
if (drag.current || !toggleView) return;
|
||||
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersectionPoint = new THREE.Vector3();
|
||||
let position = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||
if (!position) return;
|
||||
|
||||
const pointIntersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Point');
|
||||
|
||||
// const floorIntersect = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Floor-Line');
|
||||
|
||||
// if (floorIntersect && !pointIntersects) {
|
||||
|
||||
// }
|
||||
|
||||
const newPoint: Point = {
|
||||
pointUuid: THREE.MathUtils.generateUUID(),
|
||||
pointType: 'Floor',
|
||||
position: [position.x, position.y, position.z],
|
||||
layer: activeLayer
|
||||
};
|
||||
|
||||
if (snappedPosition && snappedPoint) {
|
||||
newPoint.pointUuid = snappedPoint.pointUuid;
|
||||
newPoint.position = snappedPosition;
|
||||
newPoint.layer = snappedPoint.layer;
|
||||
}
|
||||
|
||||
if (snappedPoint && snappedPoint.pointUuid === tempPoints[tempPoints.length - 1]?.pointUuid) { return }
|
||||
|
||||
if (snappedPosition && !snappedPoint) {
|
||||
newPoint.position = snappedPosition;
|
||||
}
|
||||
|
||||
if (tempPoints.length > 2 && isCreating && snappedPoint && snappedPoint.pointUuid === tempPoints[0].pointUuid) {
|
||||
const floor: Floor = {
|
||||
floorUuid: THREE.MathUtils.generateUUID(),
|
||||
floorName: "Floor",
|
||||
points: tempPoints,
|
||||
topMaterial,
|
||||
sideMaterial,
|
||||
floorDepth,
|
||||
isBeveled,
|
||||
bevelStrength,
|
||||
decals: [],
|
||||
};
|
||||
|
||||
addFloor(floor);
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
} else if (isCreating && snappedPoint && !tempPoints.some(p => p.pointUuid === snappedPoint.pointUuid)) {
|
||||
setTempPoints(prev => [...prev, newPoint]);
|
||||
setIsCreating(true);
|
||||
} else if (pointIntersects) {
|
||||
if (tempPoints.length > 2 && isCreating && pointIntersects.object.uuid === tempPoints[0].pointUuid) {
|
||||
const floor: Floor = {
|
||||
floorUuid: THREE.MathUtils.generateUUID(),
|
||||
floorName: "Floor",
|
||||
points: tempPoints,
|
||||
topMaterial,
|
||||
sideMaterial,
|
||||
floorDepth,
|
||||
isBeveled,
|
||||
bevelStrength,
|
||||
decals: [],
|
||||
};
|
||||
|
||||
addFloor(floor);
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
} else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some(p => p.pointUuid === pointIntersects.object.uuid))) {
|
||||
tempPoints.push(pointIntersects.object.userData as Point);
|
||||
setIsCreating(true);
|
||||
}
|
||||
} else {
|
||||
setTempPoints(prev => [...prev, newPoint]);
|
||||
setIsCreating(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const onContext = (event: any) => {
|
||||
event.preventDefault();
|
||||
if (isCreating) {
|
||||
if (tempPoints.length >= 3) {
|
||||
const floor: Floor = {
|
||||
floorUuid: THREE.MathUtils.generateUUID(),
|
||||
floorName: "Floor",
|
||||
points: tempPoints,
|
||||
topMaterial,
|
||||
sideMaterial,
|
||||
floorDepth,
|
||||
isBeveled,
|
||||
bevelStrength,
|
||||
decals: [],
|
||||
};
|
||||
|
||||
addFloor(floor);
|
||||
if (projectId) {
|
||||
|
||||
// API
|
||||
|
||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
|
||||
|
||||
// SOCKET
|
||||
|
||||
const data = {
|
||||
floorData: floor,
|
||||
projectId: projectId,
|
||||
versionId: selectedVersion?.versionId || '',
|
||||
userId: userId,
|
||||
organization: organization
|
||||
}
|
||||
|
||||
socket.emit('v1:model-Floor:add', data);
|
||||
|
||||
}
|
||||
}
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (toolMode === "Floor" && toggleView) {
|
||||
if (tempPoints.length === 0) {
|
||||
setSnappedPosition(null);
|
||||
setSnappedPoint(null);
|
||||
}
|
||||
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||
canvasElement.addEventListener("click", onMouseClick);
|
||||
canvasElement.addEventListener("contextmenu", onContext);
|
||||
} else {
|
||||
setTempPoints([]);
|
||||
setIsCreating(false);
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContext);
|
||||
}
|
||||
|
||||
return () => {
|
||||
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||
canvasElement.removeEventListener("click", onMouseClick);
|
||||
canvasElement.removeEventListener("contextmenu", onContext);
|
||||
};
|
||||
}, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView &&
|
||||
<>
|
||||
<group name='Floor-Reference-Points-Group'>
|
||||
{tempPoints.map((point) => (
|
||||
<ReferencePoint key={point.pointUuid} point={point} />
|
||||
))}
|
||||
</group>
|
||||
|
||||
{tempPoints.length > 0 &&
|
||||
<ReferenceFloor tempPoints={tempPoints} />
|
||||
}
|
||||
</>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorCreator
|
||||
165
app/src/modules/builder/floor/floorCreator/referenceFloor.tsx
Normal file
165
app/src/modules/builder/floor/floorCreator/referenceFloor.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import { useEffect, useRef, useState, useMemo } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { Extrude, Html } from '@react-three/drei';
|
||||
import { useBuilderStore } from '../../../../store/builder/useBuilderStore';
|
||||
import { useActiveLayer, useToolMode, useToggleView } from '../../../../store/builder/store';
|
||||
import { useDirectionalSnapping } from '../../point/helpers/useDirectionalSnapping';
|
||||
import { usePointSnapping } from '../../point/helpers/usePointSnapping';
|
||||
import ReferenceLine from '../../line/reference/referenceLine';
|
||||
|
||||
interface ReferenceFloorProps {
|
||||
tempPoints: Point[];
|
||||
}
|
||||
|
||||
function ReferenceFloor({ tempPoints }: Readonly<ReferenceFloorProps>) {
|
||||
const { floorDepth, isBeveled, bevelStrength, setSnappedPosition, setSnappedPoint } = useBuilderStore();
|
||||
const { pointer, raycaster, camera } = useThree();
|
||||
const { toolMode } = useToolMode();
|
||||
const { toggleView } = useToggleView();
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
||||
const finalPosition = useRef<[number, number, number] | null>(null);
|
||||
|
||||
const [tempFloor, setTempFloor] = useState<Floor | null>(null);
|
||||
const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position);
|
||||
|
||||
const directionalSnap = useDirectionalSnapping(currentPosition, tempPoints[tempPoints.length - 1]?.position || null);
|
||||
const { snapFloorPoint } = usePointSnapping({ uuid: 'temp-Floor', pointType: 'Floor', position: directionalSnap.position || [0, 0, 0], });
|
||||
|
||||
useFrame(() => {
|
||||
if (toolMode === 'Floor' && toggleView && tempPoints.length > 0) {
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersectionPoint = new THREE.Vector3();
|
||||
raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||
|
||||
setCurrentPosition([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z]);
|
||||
|
||||
if (!intersectionPoint) return;
|
||||
const snapped = snapFloorPoint([intersectionPoint.x, intersectionPoint.y, intersectionPoint.z], tempPoints.length > 2 ? [tempPoints[0]] : []);
|
||||
|
||||
if (snapped.isSnapped && snapped.snappedPoint) {
|
||||
finalPosition.current = snapped.position;
|
||||
setSnappedPosition(snapped.position);
|
||||
setSnappedPoint(snapped.snappedPoint);
|
||||
} else if (directionalSnap.isSnapped) {
|
||||
finalPosition.current = directionalSnap.position;
|
||||
setSnappedPosition(directionalSnap.position);
|
||||
setSnappedPoint(null);
|
||||
} else {
|
||||
finalPosition.current = [intersectionPoint.x, intersectionPoint.y, intersectionPoint.z];
|
||||
setSnappedPosition(null);
|
||||
setSnappedPoint(null);
|
||||
}
|
||||
|
||||
if (!finalPosition.current) return;
|
||||
|
||||
const floorPoints: Point[] = [
|
||||
...tempPoints,
|
||||
{
|
||||
pointUuid: 'temp-point',
|
||||
pointType: 'Floor',
|
||||
position: finalPosition.current,
|
||||
layer: activeLayer,
|
||||
},
|
||||
];
|
||||
|
||||
setTempFloor({
|
||||
floorUuid: 'temp-floor',
|
||||
floorName: 'temp-floor',
|
||||
points: floorPoints,
|
||||
topMaterial: 'default',
|
||||
sideMaterial: 'default',
|
||||
floorDepth,
|
||||
bevelStrength,
|
||||
isBeveled,
|
||||
decals: [],
|
||||
});
|
||||
|
||||
} else if (tempFloor !== null) {
|
||||
setTempFloor(null);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setTempFloor(null);
|
||||
}, [toolMode, toggleView, tempPoints.length, floorDepth, bevelStrength, isBeveled, activeLayer]);
|
||||
|
||||
const allLines = useMemo(() => {
|
||||
if (!tempFloor || tempFloor.points.length < 2) return [];
|
||||
|
||||
const lines: [Point, Point][] = [];
|
||||
const pts = tempFloor.points;
|
||||
|
||||
for (let i = 0; i < pts.length - 1; i++) {
|
||||
lines.push([pts[i], pts[i + 1]]);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}, [tempFloor]);
|
||||
|
||||
if (!tempFloor) return null;
|
||||
|
||||
return (
|
||||
<group name="Floor-Reference-Group">
|
||||
{allLines.map(([p1, p2], idx) => {
|
||||
const v1 = new THREE.Vector3(...p1.position);
|
||||
const v2 = new THREE.Vector3(...p2.position);
|
||||
const mid = new THREE.Vector3().addVectors(v1, v2).multiplyScalar(0.5);
|
||||
const dist = v1.distanceTo(v2);
|
||||
|
||||
return (
|
||||
<group key={`${p1.pointUuid}-${p2.pointUuid}`}>
|
||||
<ReferenceLine points={[p1, p2]} />
|
||||
{toggleView && (
|
||||
<Html
|
||||
position={[mid.x, 1, mid.z]}
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
>
|
||||
<div className={`distance ref-line-${idx}`}>{dist.toFixed(2)} m</div>
|
||||
</Html>
|
||||
)}
|
||||
</group>
|
||||
);
|
||||
})}
|
||||
|
||||
{tempPoints.length >= 3 && (
|
||||
<Floor floor={tempFloor.points} />
|
||||
)}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReferenceFloor;
|
||||
|
||||
|
||||
function Floor({ floor }: { floor: Point[] }) {
|
||||
const savedTheme: string | null = localStorage.getItem('theme');
|
||||
|
||||
const shape = useMemo(() => {
|
||||
const shape = new THREE.Shape();
|
||||
const points = floor.map(p => new THREE.Vector2(p.position[0], p.position[2]));
|
||||
if (points.length < 3) return null;
|
||||
shape.moveTo(points[0].x, points[0].y);
|
||||
points.forEach((pt) => { shape.lineTo(pt.x, pt.y); });
|
||||
return shape;
|
||||
}, [floor]);
|
||||
|
||||
if (!shape) return null;
|
||||
|
||||
return (
|
||||
<group name="Wall-Floor" rotation={[Math.PI / 2, 0, 0]}>
|
||||
<Extrude
|
||||
args={[shape, { depth: 0.001, bevelEnabled: false }]}
|
||||
position={[0, 0, 0]}
|
||||
receiveShadow
|
||||
>
|
||||
<meshStandardMaterial color={savedTheme === "dark" ? "#808080" : "#808080"} depthWrite={false} transparent opacity={0.3} side={THREE.DoubleSide} />
|
||||
</Extrude>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
55
app/src/modules/builder/floor/floorGroup.tsx
Normal file
55
app/src/modules/builder/floor/floorGroup.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useActiveTool, useToggleView } from '../../../store/builder/store'
|
||||
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
|
||||
import { useVersionContext } from '../version/versionContext';
|
||||
import { useSceneContext } from '../../scene/sceneContext';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import useModuleStore from '../../../store/useModuleStore';
|
||||
import FloorCreator from './floorCreator/floorCreator';
|
||||
import FloorInstances from './Instances/floorInstances';
|
||||
import { getFloorsApi } from '../../../services/factoryBuilder/floor/getFloorsApi';
|
||||
|
||||
function FloorGroup() {
|
||||
const { togglView } = useToggleView();
|
||||
const { setSelectedFloor, setSelectedDecal } = useBuilderStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { activeTool } = useActiveTool();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { floorStore } = useSceneContext();
|
||||
const { setFloors } = floorStore();
|
||||
const { projectId } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (togglView || activeModule !== 'builder') {
|
||||
setSelectedFloor(null);
|
||||
setSelectedDecal(null);
|
||||
}
|
||||
}, [togglView, activeModule, activeTool])
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId && selectedVersion) {
|
||||
getFloorsApi(projectId, selectedVersion?.versionId || '').then((floors) => {
|
||||
if (floors && floors.length > 0) {
|
||||
setFloors(floors);
|
||||
} else {
|
||||
setFloors([]);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}, [projectId, selectedVersion?.versionId])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<FloorCreator />
|
||||
|
||||
<FloorInstances />
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FloorGroup
|
||||
@@ -1,87 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
|
||||
function DeletableLineorPoint(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
hoveredDeletablePoint: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered line or point during the deletion time //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
let intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let visibleIntersectLines;
|
||||
if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); }
|
||||
const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null;
|
||||
|
||||
let visibleIntersectPoints;
|
||||
if (floorPlanGroupPoint.current) {
|
||||
visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true);
|
||||
}
|
||||
const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined;
|
||||
|
||||
function getLineColor(lineType: string | undefined): string {
|
||||
switch (lineType) {
|
||||
case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
|
||||
case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
|
||||
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
|
||||
default: return CONSTANTS.lineConfig.defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects.length > 0) {
|
||||
if (visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletablePoint.current = (visibleIntersectPoint as any).object;
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red"));
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set(new THREE.Color("red"));
|
||||
// (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5);
|
||||
} else if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
if (visibleIntersectLine && !visibleIntersectPoint) {
|
||||
if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
|
||||
if (hoveredDeletablePoint.current) {
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
|
||||
(hoveredDeletablePoint.current as any).material.uniforms.uOuterColor.value.set((hoveredDeletablePoint.current as any).userData.color);
|
||||
// hoveredDeletablePoint.current.scale.set(1, 1, 1);
|
||||
hoveredDeletablePoint.current = null;
|
||||
}
|
||||
|
||||
hoveredDeletableLine.current = (visibleIntersectLine as any).object;
|
||||
if (hoveredDeletableLine.current) {
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red");
|
||||
}
|
||||
} else if (hoveredDeletableLine.current) {
|
||||
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
|
||||
const color = getLineColor(lineType);
|
||||
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
|
||||
hoveredDeletableLine.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DeletableLineorPoint;
|
||||
@@ -1,93 +0,0 @@
|
||||
import * as Types from "../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine";
|
||||
|
||||
async function Draw(
|
||||
state: Types.ThreeState,
|
||||
plane: Types.RefMesh,
|
||||
cursorPosition: Types.Vector3,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
setRefTextUpdate: any,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
toolMode: Types.String,
|
||||
): Promise<void> {
|
||||
|
||||
////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
const intersects = state.raycaster.intersectObject(plane.current, true);
|
||||
|
||||
if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Floor")) {
|
||||
const intersectionPoint = intersects[0].point;
|
||||
cursorPosition.copy(intersectionPoint);
|
||||
const snapThreshold = 1;
|
||||
|
||||
if (line.current.length === 0) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
const canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName))
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
ispreSnapped.current = true;
|
||||
isSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
}
|
||||
}
|
||||
} else if (line.current.length > 0 && line.current[0]) {
|
||||
for (const point of floorPlanGroupPoint.current.children) {
|
||||
const pointType = point.userData.type;
|
||||
|
||||
let canSnap =
|
||||
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
|
||||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName))
|
||||
|
||||
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) {
|
||||
cursorPosition.copy(point.position);
|
||||
snappedPoint.current = point.position;
|
||||
isSnapped.current = true;
|
||||
ispreSnapped.current = false;
|
||||
isSnappedUUID.current = point.uuid;
|
||||
break;
|
||||
} else {
|
||||
isSnapped.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
createAndMoveReferenceLine(
|
||||
line.current[0][0],
|
||||
cursorPosition,
|
||||
isSnapped,
|
||||
ispreSnapped,
|
||||
line,
|
||||
setRefTextUpdate,
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
Tube,
|
||||
anglesnappedPoint,
|
||||
isAngleSnapped
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Draw;
|
||||
@@ -1,62 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import texturePath from "../../../../assets/textures/floor/white.png";
|
||||
import texturePathDark from "../../../../assets/textures/floor/black.png";
|
||||
|
||||
// Cache for materials
|
||||
const materialCache = new Map<string, THREE.Material>();
|
||||
|
||||
export default function addFloorToScene(
|
||||
shape: THREE.Shape,
|
||||
layer: number,
|
||||
floorGroup: Types.RefGroup,
|
||||
userData: any,
|
||||
) {
|
||||
const savedTheme: string | null = localStorage.getItem('theme');
|
||||
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
|
||||
const textureScale = CONSTANTS.floorConfig.textureScale;
|
||||
|
||||
const materialKey = `floorMaterial_${textureScale}`;
|
||||
|
||||
let material: THREE.Material;
|
||||
|
||||
if (materialCache.has(materialKey)) {
|
||||
material = materialCache.get(materialKey) as THREE.Material;
|
||||
} else {
|
||||
const floorTexture = textureLoader.load(savedTheme === "dark" ? texturePathDark : texturePath);
|
||||
// const floorTexture = textureLoader.load(texturePath);
|
||||
|
||||
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
|
||||
floorTexture.repeat.set(textureScale, textureScale);
|
||||
floorTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
|
||||
material = new THREE.MeshStandardMaterial({
|
||||
map: floorTexture,
|
||||
side: THREE.DoubleSide,
|
||||
});
|
||||
|
||||
materialCache.set(materialKey, material);
|
||||
}
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false,
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.receiveShadow = true;
|
||||
mesh.position.y = (layer) * CONSTANTS.wallConfig.height;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Floor_Layer_${layer}`;
|
||||
|
||||
// Store UUIDs for debugging or future processing
|
||||
mesh.userData.uuids = userData;
|
||||
|
||||
floorGroup.current.add(mesh);
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
import addLineToScene from "../lines/addLineToScene";
|
||||
import splitLine from "../lines/splitLine";
|
||||
import removeReferenceLine from "../lines/removeReferenceLine";
|
||||
import getClosestIntersection from "../lines/getClosestIntersection";
|
||||
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function drawOnlyFloor(
|
||||
raycaster: THREE.Raycaster,
|
||||
state: Types.ThreeState,
|
||||
camera: THREE.Camera,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
onlyFloorline: Types.RefOnlyFloorLine,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
const { userId, organization, email } = getUserData();
|
||||
const intersects = raycaster.intersectObject(plane.current, true);
|
||||
const intersectsLines = raycaster.intersectObjects(
|
||||
floorPlanGroupLine.current.children,
|
||||
true
|
||||
);
|
||||
const intersectsPoint = raycaster.intersectObjects(
|
||||
floorPlanGroupPoint.current.children,
|
||||
true
|
||||
);
|
||||
const VisibleintersectsPoint = intersectsPoint.find(
|
||||
(intersect) => intersect.object.visible
|
||||
);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName
|
||||
);
|
||||
if (
|
||||
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
|
||||
intersectsLines.length > 0 &&
|
||||
!isSnapped.current &&
|
||||
!ispreSnapped.current
|
||||
) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (
|
||||
visibleIntersect &&
|
||||
(intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.floorName ||
|
||||
intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName)
|
||||
) {
|
||||
let pointColor, lineColor;
|
||||
if (
|
||||
intersectsLines[0].object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
) {
|
||||
pointColor = CONSTANTS.pointConfig.wallOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.wallColor;
|
||||
} else {
|
||||
pointColor = CONSTANTS.pointConfig.floorOuterColor;
|
||||
lineColor = CONSTANTS.lineConfig.floorColor;
|
||||
}
|
||||
let IntersectsPoint = new THREE.Vector3(
|
||||
intersects[0].point.x,
|
||||
0.01,
|
||||
intersects[0].point.z
|
||||
);
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint =
|
||||
visibleIntersect.object.geometry.parameters.path.getPoints(
|
||||
CONSTANTS.lineConfig.lineIntersectionPoints
|
||||
);
|
||||
let intersectionPoint = getClosestIntersection(
|
||||
ThroughPoint,
|
||||
IntersectsPoint
|
||||
);
|
||||
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
pointColor,
|
||||
lineColor,
|
||||
intersectsLines[0].object.userData.linePoints[0][3],
|
||||
projectId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.floorName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
projectId,
|
||||
versionId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.floorColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
|
||||
removeReferenceLine(
|
||||
floorPlanGroup,
|
||||
ReferenceLineMesh,
|
||||
LineCreated,
|
||||
line
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects.length > 0 && intersectsLines.length === 0) {
|
||||
////////// Clicked on an empty place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.floorOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.floorName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.floorName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
onlyFloorline.current.push(line.current as Types.Line);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.floorColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
const lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
////////// Add this to stop the drawing mode after snapping //////////
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
onlyFloorlines.current.push(onlyFloorline.current);
|
||||
onlyFloorline.current = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawOnlyFloor;
|
||||
@@ -1,50 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import addRoofToScene from '../roofs/addRoofToScene';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import loadOnlyFloors from './loadOnlyFloors';
|
||||
import addFloorToScene from './addFloorToScene';
|
||||
import getRoomsFromLines from '../lines/getRoomsFromLines';
|
||||
|
||||
async function loadFloor(
|
||||
lines: Types.RefLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
): Promise<void> {
|
||||
|
||||
if (!floorGroup.current) return;
|
||||
|
||||
floorGroup.current.children = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
// Only Floor Polygons
|
||||
loadOnlyFloors(floorGroup, linesByLayer, layer);
|
||||
|
||||
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
|
||||
|
||||
rooms.forEach(({ coordinates: room, layer }) => {
|
||||
const userData = room.map(point => point.uuid);
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(room[0].position.x, room[0].position.z);
|
||||
room.forEach(point => shape.lineTo(point.position.x, point.position.z));
|
||||
shape.closePath();
|
||||
|
||||
// Floor Polygons
|
||||
addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData);
|
||||
|
||||
// Roof Polygons
|
||||
addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default loadFloor;
|
||||
@@ -1,183 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function loadOnlyFloors(
|
||||
floorGroup: Types.RefGroup,
|
||||
linesByLayer: any,
|
||||
layer: any,
|
||||
): void {
|
||||
|
||||
////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well //////////
|
||||
|
||||
let floorsInLayer = linesByLayer[layer];
|
||||
floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName);
|
||||
const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position)));
|
||||
|
||||
function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) {
|
||||
const floorpolygons = [];
|
||||
const connectedLines = [];
|
||||
const unprocessedLines = [...FloorLineFeatures]; // Copy the features
|
||||
|
||||
while (unprocessedLines.length > 0) {
|
||||
const currentLine = unprocessedLines.pop();
|
||||
const coordinates = currentLine.geometry.coordinates;
|
||||
|
||||
// Check if the line is closed (forms a polygon)
|
||||
if (
|
||||
coordinates[0][0] === coordinates[coordinates.length - 1][0] &&
|
||||
coordinates[0][1] === coordinates[coordinates.length - 1][1]
|
||||
) {
|
||||
floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the line connects to another line
|
||||
let connected = false;
|
||||
for (let i = unprocessedLines.length - 1; i >= 0; i--) {
|
||||
const otherCoordinates = unprocessedLines[i].geometry.coordinates;
|
||||
|
||||
// Check if lines share a start or end point
|
||||
if (
|
||||
coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] &&
|
||||
coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
} else if (
|
||||
coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] &&
|
||||
coordinates[coordinates.length - 1][1] === otherCoordinates[0][1]
|
||||
) {
|
||||
// Merge lines
|
||||
const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)];
|
||||
unprocessedLines[i] = turf.lineString(mergedCoordinates);
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
connectedLines.push(currentLine); // Add unconnected line as-is
|
||||
}
|
||||
}
|
||||
|
||||
return { floorpolygons, connectedLines };
|
||||
}
|
||||
|
||||
const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures);
|
||||
|
||||
function convertConnectedLinesToPolygons(connectedLines: any) {
|
||||
return connectedLines.map((line: any) => {
|
||||
const coordinates = line.geometry.coordinates;
|
||||
|
||||
// If the line has more than two points, close the polygon
|
||||
if (coordinates.length > 2) {
|
||||
const firstPoint = coordinates[0];
|
||||
const lastPoint = coordinates[coordinates.length - 1];
|
||||
|
||||
// Check if already closed; if not, close it
|
||||
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
|
||||
coordinates.push(firstPoint);
|
||||
}
|
||||
|
||||
// Convert the closed line into a polygon
|
||||
return turf.polygon([coordinates]);
|
||||
}
|
||||
|
||||
// If not enough points for a polygon, return the line unchanged
|
||||
return line;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines);
|
||||
|
||||
if (convertedConnectedPolygons.length > 0) {
|
||||
const validPolygons = convertedConnectedPolygons.filter(
|
||||
(polygon: any) => polygon.geometry?.type === "Polygon"
|
||||
);
|
||||
|
||||
if (validPolygons.length > 0) {
|
||||
floorpolygons.push(...validPolygons);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) {
|
||||
return floorpolygons.map((polygon: any) => {
|
||||
const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon)
|
||||
|
||||
// Map each coordinate back to its original structure
|
||||
const mappedPoints = coordinates.map((coord: [number, number]) => {
|
||||
const [x, z] = coord;
|
||||
|
||||
// Find the original point matching this coordinate
|
||||
const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z);
|
||||
|
||||
if (!originalPoint) {
|
||||
throw new Error(`Original point for coordinate [${x}, ${z}] not found.`);
|
||||
}
|
||||
|
||||
return originalPoint;
|
||||
});
|
||||
|
||||
// Create pairs of consecutive points
|
||||
const pairs: typeof originalLines = [];
|
||||
for (let i = 0; i < mappedPoints.length - 1; i++) {
|
||||
pairs.push([mappedPoints[i], mappedPoints[i + 1]]);
|
||||
}
|
||||
|
||||
return pairs;
|
||||
});
|
||||
}
|
||||
|
||||
const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer);
|
||||
|
||||
convertedFloorPolygons.forEach((floor) => {
|
||||
const points: THREE.Vector3[] = [];
|
||||
|
||||
floor.forEach((lineSegment) => {
|
||||
const startPoint = lineSegment[0][0];
|
||||
points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z));
|
||||
});
|
||||
|
||||
const lastLine = floor[floor.length - 1];
|
||||
const endPoint = lastLine[1][0];
|
||||
points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z));
|
||||
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(points[0].x, points[0].z);
|
||||
|
||||
points.forEach(point => shape.lineTo(point.x, point.z));
|
||||
shape.closePath();
|
||||
|
||||
const extrudeSettings = {
|
||||
depth: CONSTANTS.floorConfig.height,
|
||||
bevelEnabled: false
|
||||
};
|
||||
|
||||
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
|
||||
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height;
|
||||
mesh.rotateX(Math.PI / 2);
|
||||
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
|
||||
|
||||
mesh.userData = floor;
|
||||
floorGroup?.current?.add(mesh);
|
||||
});
|
||||
}
|
||||
|
||||
export default loadOnlyFloors;
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateFloorLines(
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }
|
||||
): void {
|
||||
|
||||
////////// Update onlyFloorlines.current if it contains the dragged point //////////
|
||||
|
||||
onlyFloorlines.current.forEach((floorline) => {
|
||||
floorline.forEach((line) => {
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === DragedPoint.uuid) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default updateFloorLines;
|
||||
@@ -1,104 +0,0 @@
|
||||
import { toast } from "react-toastify";
|
||||
import RemoveConnectedLines from "../lines/removeConnectedLines";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
|
||||
|
||||
async function DeleteLayer(
|
||||
removedLayer: Types.Number,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
floorGroup: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
setRemovedLayer: Types.setRemoveLayerSetState,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
|
||||
|
||||
const removedLines: Types.Lines = lines.current.filter(
|
||||
(line) => line[0][2] === removedLayer
|
||||
);
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
//REST
|
||||
|
||||
// await deleteLayer(organization, removedLayer);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
layer: removedLayer,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:delete:layer", data);
|
||||
|
||||
////////// Remove Points and lines from the removed layer //////////
|
||||
|
||||
removedLines.forEach((line) => {
|
||||
line.forEach((removedPoint) => {
|
||||
RemoveConnectedLines(
|
||||
removedPoint[1],
|
||||
floorPlanGroupLine,
|
||||
floorPlanGroupPoint,
|
||||
setDeletedLines,
|
||||
lines
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
////////// Update the remaining lines layer values in the userData and in lines.current //////////
|
||||
|
||||
let remaining = lines.current.filter((line) => line[0][2] !== removedLayer);
|
||||
let updatedLines: Types.Lines = [];
|
||||
remaining.forEach((line) => {
|
||||
let newLines: Types.Line = [...line];
|
||||
if (newLines[0][2] > removedLayer) {
|
||||
newLines[0][2] -= 1;
|
||||
newLines[1][2] -= 1;
|
||||
}
|
||||
|
||||
const matchingLine = floorPlanGroupLine.current.children.find(
|
||||
(l) =>
|
||||
l.userData.linePoints[0][1] === line[0][1] &&
|
||||
l.userData.linePoints[1][1] === line[1][1]
|
||||
);
|
||||
if (matchingLine) {
|
||||
const updatedUserData = matchingLine.userData;
|
||||
updatedUserData.linePoints[0][2] = newLines[0][2];
|
||||
updatedUserData.linePoints[1][2] = newLines[1][2];
|
||||
}
|
||||
updatedLines.push(newLines);
|
||||
});
|
||||
|
||||
lines.current = updatedLines;
|
||||
localStorage.setItem("Lines", JSON.stringify(lines.current));
|
||||
|
||||
////////// Also remove OnlyFloorLines and update it in localstorage //////////
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
|
||||
return floor[0][0][2] !== removedLayer;
|
||||
});
|
||||
const meshToRemove: any = floorGroup.current?.children.find(
|
||||
(mesh) => mesh.name === `Only_Floor_Line_${removedLayer}`
|
||||
);
|
||||
if (meshToRemove) {
|
||||
(<any>meshToRemove.material).dispose();
|
||||
(<any>meshToRemove.geometry).dispose();
|
||||
floorGroup.current?.remove(meshToRemove);
|
||||
}
|
||||
|
||||
echo.success("Layer Removed!");
|
||||
setRemovedLayer(null);
|
||||
}
|
||||
export default DeleteLayer;
|
||||
@@ -1,35 +0,0 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function Layer2DVisibility(
|
||||
activeLayer: Types.Number,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl
|
||||
): void {
|
||||
|
||||
if (floorPlanGroup.current && dragPointControls.current) {
|
||||
currentLayerPoint.current = [];
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
|
||||
const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh;
|
||||
const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh;
|
||||
|
||||
if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) {
|
||||
point1.visible = false;
|
||||
point2.visible = false;
|
||||
line.visible = false;
|
||||
} else {
|
||||
point1.visible = true;
|
||||
point2.visible = true;
|
||||
line.visible = true;
|
||||
currentLayerPoint.current.push(point1, point2);
|
||||
}
|
||||
});
|
||||
dragPointControls.current!.objects = currentLayerPoint.current;
|
||||
}
|
||||
}
|
||||
|
||||
export default Layer2DVisibility;
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addLineToScene(
|
||||
start: Types.Vector3,
|
||||
end: Types.Vector3,
|
||||
colour: Types.Color,
|
||||
userData: Types.UserData,
|
||||
floorPlanGroupLine: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData //////////
|
||||
|
||||
const path = new THREE.CatmullRomCurve3([start, end]);
|
||||
const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: colour });
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
floorPlanGroupLine.current.add(mesh);
|
||||
|
||||
mesh.userData.linePoints = userData;
|
||||
}
|
||||
|
||||
export default addLineToScene;
|
||||
@@ -1,98 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function createAndMoveReferenceLine(
|
||||
point: Types.Vector3,
|
||||
cursorPosition: Types.Vector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
line: Types.RefLine,
|
||||
setRefTextUpdate: Types.NumberIncrementState,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
Tube: Types.RefTubeGeometry,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean
|
||||
): void {
|
||||
|
||||
////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle //////////
|
||||
|
||||
const startPoint = point;
|
||||
|
||||
const dx = cursorPosition.x - startPoint.x;
|
||||
const dz = cursorPosition.z - startPoint.z;
|
||||
let angle = Math.atan2(dz, dx);
|
||||
|
||||
angle = (angle * 180) / Math.PI;
|
||||
angle = (angle + 360) % 360;
|
||||
|
||||
const snapAngles = [0, 90, 180, 270, 360];
|
||||
const snapThreshold = 2.5;
|
||||
|
||||
const closestSnapAngle = snapAngles.reduce((prev, curr) =>
|
||||
Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev
|
||||
);
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) {
|
||||
if (Math.abs(closestSnapAngle - angle) <= snapThreshold) {
|
||||
const snappedAngleRad = (closestSnapAngle * Math.PI) / 180;
|
||||
const distance = Math.sqrt(dx * dx + dz * dz);
|
||||
const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad);
|
||||
const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad);
|
||||
|
||||
if (
|
||||
cursorPosition.distanceTo(
|
||||
new THREE.Vector3(snappedX, 0.01, snappedZ)
|
||||
) < 2
|
||||
) {
|
||||
cursorPosition.set(snappedX, 0.01, snappedZ);
|
||||
isAngleSnapped.current = true;
|
||||
anglesnappedPoint.current = new THREE.Vector3(
|
||||
snappedX,
|
||||
0.01,
|
||||
snappedZ
|
||||
);
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
} else {
|
||||
isAngleSnapped.current = false;
|
||||
anglesnappedPoint.current = null;
|
||||
}
|
||||
|
||||
if (!LineCreated.current) {
|
||||
setRefTextUpdate((prevUpdate) => prevUpdate - 1);
|
||||
const path = new THREE.LineCurve3(startPoint, cursorPosition);
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor });
|
||||
ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material);
|
||||
ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName;
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
floorPlanGroup.current?.add(ReferenceLineMesh.current);
|
||||
LineCreated.current = true;
|
||||
} else {
|
||||
if (ReferenceLineMesh.current) {
|
||||
const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z));
|
||||
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
|
||||
if (ReferenceLineMesh.current) {
|
||||
ReferenceLineMesh.current.userData = {
|
||||
linePoints: { startPoint, cursorPosition },
|
||||
};
|
||||
ReferenceLineMesh.current.geometry.dispose();
|
||||
ReferenceLineMesh.current.geometry = Tube.current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default createAndMoveReferenceLine;
|
||||
@@ -1,92 +0,0 @@
|
||||
import { Socket } from "socket.io-client";
|
||||
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
import { toast } from "react-toastify";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
function deleteLine(
|
||||
hoveredDeletableLine: Types.RefMesh,
|
||||
onlyFloorlines: Types.RefOnlyFloorLines,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): void {
|
||||
const { userId, organization, email } = getUserData();
|
||||
////////// Deleting a line and the points if they are not connected to any other line //////////
|
||||
|
||||
if (!hoveredDeletableLine.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linePoints = hoveredDeletableLine.current.userData.linePoints;
|
||||
const connectedpoints = [linePoints[0][1], linePoints[1][1]];
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": linePoints[0][1] },
|
||||
// { "uuid": linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
line: [{ uuid: linePoints[0][1] }, { uuid: linePoints[1][1] }],
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:delete", data);
|
||||
|
||||
onlyFloorlines.current = onlyFloorlines.current
|
||||
.map((floorline) =>
|
||||
floorline.filter(
|
||||
(line) =>
|
||||
line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]
|
||||
)
|
||||
)
|
||||
.filter((floorline) => floorline.length > 0);
|
||||
|
||||
lines.current = lines.current.filter((item) => item !== linePoints);
|
||||
(<any>hoveredDeletableLine.current.material).dispose();
|
||||
(<any>hoveredDeletableLine.current.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
|
||||
setDeletedLines([linePoints]);
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints;
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
echo.success("Line Removed!");
|
||||
}
|
||||
|
||||
export default deleteLine;
|
||||
@@ -1,226 +0,0 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { getLines } from "../../../../../services/factoryBuilder/lines/getLinesApi";
|
||||
import * as THREE from "three";
|
||||
import {
|
||||
useActiveLayer,
|
||||
useDeletedLines,
|
||||
useNewLines,
|
||||
useRoomsState,
|
||||
useToggleView,
|
||||
} from "../../../../../store/builder/store";
|
||||
import objectLinesToArray from "../lineConvertions/objectLinesToArray";
|
||||
import { Html } from "@react-three/drei";
|
||||
import { Vector2 } from "three";
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
import getRoomsFromLines from "../getRoomsFromLines";
|
||||
import * as turf from '@turf/turf';
|
||||
import { useParams } from "react-router-dom";
|
||||
import { getUserData } from "../../../../../functions/getUserData";
|
||||
import { useVersionContext } from "../../../version/versionContext";
|
||||
|
||||
const DistanceText = () => {
|
||||
const [lines, setLines] = useState<
|
||||
{
|
||||
distance: string;
|
||||
position: THREE.Vector3;
|
||||
userData: Types.Line;
|
||||
layer: string;
|
||||
}[]
|
||||
>([]);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
const { toggleView } = useToggleView();
|
||||
const { newLines, setNewLines } = useNewLines();
|
||||
const { deletedLines, setDeletedLines } = useDeletedLines();
|
||||
const [linesState, setLinesState] = useState<Types.Lines>([]);
|
||||
const { roomsState, setRoomsState } = useRoomsState();
|
||||
const { selectedVersionStore } = useVersionContext();
|
||||
const { selectedVersion } = selectedVersionStore();
|
||||
const { projectId } = useParams();
|
||||
const { organization, email } = getUserData();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (linesState.length === 0) return;
|
||||
const getLines = async () => {
|
||||
const points3D = linesState.map(line => {
|
||||
const startPoint = line[0][0]; // First point of each wall line
|
||||
return [startPoint.x, 0, startPoint.z];
|
||||
});
|
||||
|
||||
// Ensure the polygon is closed
|
||||
if (
|
||||
points3D[0][0] !== points3D[points3D.length - 1][0] ||
|
||||
points3D[0][1] !== points3D[points3D.length - 1][1]
|
||||
) {
|
||||
points3D.push(points3D[0]);
|
||||
}
|
||||
|
||||
// Convert to 2D for turf (x, z)
|
||||
const coords2D = points3D.map(p => [p[0], p[1]]);
|
||||
|
||||
const projected = points3D.map((p: any) => new Vector2(p[0], p[1]));
|
||||
|
||||
// Shoelace formula for 2D polygon
|
||||
let area = 0;
|
||||
const n = projected.length;
|
||||
for (let i = 0; i < n - 1; i++) {
|
||||
const curr = projected[i];
|
||||
const next = projected[i + 1];
|
||||
area += curr.x * next.y - next.x * curr.y;
|
||||
|
||||
}
|
||||
|
||||
// return Math.abs(area) / 2;
|
||||
|
||||
// Build polygon and compute area
|
||||
// const polygon = turf.polygon([coords2D]);
|
||||
// const area = turf.area(polygon);
|
||||
// const area = computeAreaFrom3DPoints(coords2D)
|
||||
|
||||
//
|
||||
if (lines.length > 2) {
|
||||
const linesByLayer = linesState.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
|
||||
setRoomsState(rooms)
|
||||
}
|
||||
}
|
||||
}
|
||||
getLines();
|
||||
}, [linesState, roomsState])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!email || !selectedVersion) return;
|
||||
|
||||
getLines(organization, projectId, selectedVersion?.versionId || '').then((data) => {
|
||||
data = objectLinesToArray(data);
|
||||
setLinesState(data);
|
||||
|
||||
const lines = data
|
||||
.filter((line: Types.Line) => line[0][2] === activeLayer)
|
||||
.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(
|
||||
line[0][0].x,
|
||||
line[0][0].y,
|
||||
line[0][0].z
|
||||
);
|
||||
const point2 = new THREE.Vector3(
|
||||
line[1][0].x,
|
||||
line[1][0].y,
|
||||
line[1][0].z
|
||||
);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3()
|
||||
.addVectors(point1, point2)
|
||||
.divideScalar(2);
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines(lines);
|
||||
});
|
||||
}, [activeLayer, selectedVersion?.versionId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (newLines.length > 0) {
|
||||
if (newLines[0][0][2] !== activeLayer) return;
|
||||
const newLinesData = newLines.map((line: Types.Line) => {
|
||||
const point1 = new THREE.Vector3(
|
||||
line[0][0].x,
|
||||
line[0][0].y,
|
||||
line[0][0].z
|
||||
);
|
||||
const point2 = new THREE.Vector3(
|
||||
line[1][0].x,
|
||||
line[1][0].y,
|
||||
line[1][0].z
|
||||
);
|
||||
const distance = point1.distanceTo(point2);
|
||||
const midpoint = new THREE.Vector3()
|
||||
.addVectors(point1, point2)
|
||||
.divideScalar(2);
|
||||
|
||||
return {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
});
|
||||
setLines((prevLines) => [...prevLines, ...newLinesData]);
|
||||
setLinesState((prevLines) => [...prevLines, ...newLines]);
|
||||
setNewLines([]);
|
||||
}
|
||||
}, [newLines, activeLayer]);
|
||||
|
||||
useEffect(() => {
|
||||
if ((deletedLines as Types.Lines).length > 0) {
|
||||
setLines((prevLines) =>
|
||||
prevLines.filter(
|
||||
(line) =>
|
||||
!deletedLines.some(
|
||||
(deletedLine: any) =>
|
||||
deletedLine[0][1] === line.userData[0][1] &&
|
||||
deletedLine[1][1] === line.userData[1][1]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
setLinesState(prev =>
|
||||
prev.filter(line =>
|
||||
!(deletedLines as Types.Lines).some(
|
||||
deleted =>
|
||||
line[0][1] === deleted[0][1] && line[1][1] === deleted[1][1]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
setDeletedLines([]);
|
||||
setRoomsState([])
|
||||
}
|
||||
}, [deletedLines]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{toggleView && (
|
||||
<group name="Distance_Text">
|
||||
{lines.map((text) => (
|
||||
<Html
|
||||
// data
|
||||
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
|
||||
userData={text.userData}
|
||||
position={[text.position.x, 1, text.position.z]}
|
||||
// class
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
// other
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
>
|
||||
<div
|
||||
key={`${text.userData[0][1]}_${text.userData[1][1]}`}
|
||||
className={`distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`}
|
||||
>
|
||||
{text.distance} m
|
||||
</div>
|
||||
</Html>
|
||||
))}
|
||||
</group>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DistanceText;
|
||||
@@ -1,71 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
import { Html } from "@react-three/drei";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useActiveLayer } from "../../../../../store/builder/store";
|
||||
|
||||
const ReferenceDistanceText = ({ line }: { line: any }) => {
|
||||
interface TextState {
|
||||
distance: string;
|
||||
position: THREE.Vector3;
|
||||
userData: any;
|
||||
layer: any;
|
||||
}
|
||||
|
||||
const [text, setTexts] = useState<TextState | null>(null);
|
||||
const { activeLayer } = useActiveLayer();
|
||||
|
||||
useEffect(() => {
|
||||
if (line) {
|
||||
if (line.parent === null) {
|
||||
setTexts(null);
|
||||
return;
|
||||
}
|
||||
const distance = line.userData.linePoints.cursorPosition.distanceTo(
|
||||
line.userData.linePoints.startPoint
|
||||
);
|
||||
const midpoint = new THREE.Vector3()
|
||||
.addVectors(
|
||||
line.userData.linePoints.cursorPosition,
|
||||
line.userData.linePoints.startPoint
|
||||
)
|
||||
.divideScalar(2);
|
||||
const newTexts = {
|
||||
distance: distance.toFixed(1),
|
||||
position: midpoint,
|
||||
userData: line,
|
||||
layer: activeLayer,
|
||||
};
|
||||
setTexts(newTexts);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group name="Reference_Distance_Text">
|
||||
<mesh>
|
||||
{text !== null && (
|
||||
<Html
|
||||
// data
|
||||
key={text.distance}
|
||||
userData={text.userData}
|
||||
position={[text.position.x, 1, text.position.z]}
|
||||
// class
|
||||
wrapperClass="distance-text-wrapper"
|
||||
className="distance-text"
|
||||
// other
|
||||
zIndexRange={[1, 0]}
|
||||
prepend
|
||||
sprite
|
||||
>
|
||||
<div
|
||||
className={`Reference_Distance line-${text.userData.userData}`}
|
||||
>
|
||||
{text.distance} m
|
||||
</div>
|
||||
</Html>
|
||||
)}
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReferenceDistanceText;
|
||||
@@ -1,245 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
import addLineToScene from "./addLineToScene";
|
||||
import splitLine from "./splitLine";
|
||||
import removeReferenceLine from "./removeReferenceLine";
|
||||
import getClosestIntersection from "./getClosestIntersection";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from "./lineConvertions/arrayLineToObject";
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
|
||||
async function drawWall(
|
||||
raycaster: THREE.Raycaster,
|
||||
plane: Types.RefMesh,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
snappedPoint: Types.RefVector3,
|
||||
isSnapped: Types.RefBoolean,
|
||||
isSnappedUUID: Types.RefString,
|
||||
line: Types.RefLine,
|
||||
ispreSnapped: Types.RefBoolean,
|
||||
anglesnappedPoint: Types.RefVector3,
|
||||
isAngleSnapped: Types.RefBoolean,
|
||||
lines: Types.RefLines,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
setNewLines: any,
|
||||
setDeletedLines: any,
|
||||
activeLayer: Types.Number,
|
||||
socket: Socket<any>,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): Promise<void> {
|
||||
const { userId, organization, email } = getUserData();
|
||||
////////// Creating lines Based on the positions clicked //////////
|
||||
|
||||
////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
|
||||
|
||||
if (!plane.current) return;
|
||||
let intersects = raycaster.intersectObject(plane.current, true);
|
||||
|
||||
let intersectsLines = raycaster.intersectObjects(
|
||||
floorPlanGroupLine.current.children,
|
||||
true
|
||||
);
|
||||
let intersectsPoint = raycaster.intersectObjects(
|
||||
floorPlanGroupPoint.current.children,
|
||||
true
|
||||
);
|
||||
|
||||
const VisibleintersectsPoint = intersectsPoint.find(
|
||||
(intersect) => intersect.object.visible
|
||||
);
|
||||
const visibleIntersect = intersectsLines.find(
|
||||
(intersect) =>
|
||||
intersect.object.visible &&
|
||||
intersect.object.name !== CONSTANTS.lineConfig.referenceName &&
|
||||
intersect.object.userData.linePoints[0][3] ===
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
|
||||
if (
|
||||
(intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) &&
|
||||
intersectsLines.length > 0 &&
|
||||
!isSnapped.current &&
|
||||
!ispreSnapped.current
|
||||
) {
|
||||
////////// Clicked on a preexisting Line //////////
|
||||
|
||||
if (visibleIntersect && intersects) {
|
||||
let IntersectsPoint = new THREE.Vector3(
|
||||
intersects[0].point.x,
|
||||
0.01,
|
||||
intersects[0].point.z
|
||||
);
|
||||
|
||||
if (isAngleSnapped.current && anglesnappedPoint.current) {
|
||||
IntersectsPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (visibleIntersect.object instanceof THREE.Mesh) {
|
||||
const ThroughPoint =
|
||||
visibleIntersect.object.geometry.parameters.path.getPoints(
|
||||
CONSTANTS.lineConfig.lineIntersectionPoints
|
||||
);
|
||||
let intersectionPoint = getClosestIntersection(
|
||||
ThroughPoint,
|
||||
IntersectsPoint
|
||||
);
|
||||
|
||||
if (intersectionPoint) {
|
||||
const newLines = splitLine(
|
||||
visibleIntersect,
|
||||
intersectionPoint,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lines,
|
||||
setDeletedLines,
|
||||
floorPlanGroupLine,
|
||||
socket,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
projectId,
|
||||
versionId
|
||||
);
|
||||
setNewLines([newLines[0], newLines[1]]);
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([newLines[0], newLines[1], line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intersects && intersects.length > 0) {
|
||||
////////// Clicked on a emply place or a point //////////
|
||||
|
||||
let intersectionPoint = intersects[0].point;
|
||||
|
||||
if (
|
||||
isAngleSnapped.current &&
|
||||
line.current.length > 0 &&
|
||||
anglesnappedPoint.current
|
||||
) {
|
||||
intersectionPoint = anglesnappedPoint.current;
|
||||
}
|
||||
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
if (ispreSnapped.current && snappedPoint.current) {
|
||||
intersectionPoint = snappedPoint.current;
|
||||
}
|
||||
|
||||
if (!isSnapped.current && !ispreSnapped.current) {
|
||||
addPointToScene(
|
||||
intersectionPoint,
|
||||
CONSTANTS.pointConfig.wallOuterColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
CONSTANTS.lineConfig.wallName
|
||||
);
|
||||
} else {
|
||||
ispreSnapped.current = false;
|
||||
isSnapped.current = false;
|
||||
}
|
||||
|
||||
(line.current as Types.Line).push([
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
isSnappedUUID.current!,
|
||||
activeLayer,
|
||||
CONSTANTS.lineConfig.wallName,
|
||||
]);
|
||||
|
||||
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
|
||||
const data = arrayLineToObject(line.current as Types.Line);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, data.layer!, data.line!, data.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input = {
|
||||
organization,
|
||||
layer: data.layer,
|
||||
line: data.line,
|
||||
type: data.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input);
|
||||
|
||||
setNewLines([line.current]);
|
||||
lines.current.push(line.current as Types.Line);
|
||||
addLineToScene(
|
||||
line.current[0][0],
|
||||
line.current[1][0],
|
||||
CONSTANTS.lineConfig.wallColor,
|
||||
line.current,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
let lastPoint = line.current[line.current.length - 1];
|
||||
line.current = [lastPoint];
|
||||
}
|
||||
if (isSnapped.current) {
|
||||
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default drawWall;
|
||||
@@ -1,86 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as turf from '@turf/turf';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
async function getRoomsFromLines(lines: Types.RefLines) {
|
||||
const rooms: Types.Rooms = [];
|
||||
|
||||
if (lines.current.length > 2) {
|
||||
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
|
||||
const layer = pair[0][2];
|
||||
if (!acc[layer]) acc[layer] = [];
|
||||
acc[layer].push(pair);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
////////// Use turf.polygonize to create polygons from the line points //////////
|
||||
|
||||
for (const layer in linesByLayer) {
|
||||
|
||||
let linesInLayer = linesByLayer[layer];
|
||||
linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
|
||||
const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
|
||||
pair.map((point) => ({
|
||||
position: [point[0].x, point[0].z],
|
||||
uuid: point[1]
|
||||
}))
|
||||
);
|
||||
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
|
||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||
|
||||
let union: any[] = [];
|
||||
|
||||
polygons.features.forEach((feature) => {
|
||||
union.push(feature);
|
||||
});
|
||||
|
||||
if (union.length > 1) {
|
||||
const unionResult = turf.union(turf.featureCollection(union));
|
||||
if (unionResult?.geometry.type === "MultiPolygon") {
|
||||
unionResult?.geometry.coordinates.forEach((poly) => {
|
||||
const Coordinates = poly[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
});
|
||||
} else if (unionResult?.geometry.type === "Polygon") {
|
||||
const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
|
||||
}
|
||||
} else if (union.length === 1) {
|
||||
const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
|
||||
const matchingPoint = result.flat().find(r =>
|
||||
r.position[0].toFixed(10) === x.toFixed(10) &&
|
||||
r.position[1].toFixed(10) === z.toFixed(10)
|
||||
);
|
||||
return {
|
||||
position: new THREE.Vector3(x, 0, z),
|
||||
uuid: matchingPoint ? matchingPoint.uuid : ''
|
||||
};
|
||||
});
|
||||
rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rooms;
|
||||
}
|
||||
|
||||
export default getRoomsFromLines;
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLineToObject(array: Types.Line) {
|
||||
if (!Array.isArray(array)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = array[0][2];
|
||||
const commonType = array[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = array.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import * as Types from "../../../../../types/world/worldTypes";
|
||||
|
||||
export default function arrayLinesToObject(array: Array<Types.Line>) {
|
||||
if (!Array.isArray(array)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array.map((lineArray) => {
|
||||
if (!Array.isArray(lineArray)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract common properties from the first point
|
||||
const commonLayer = lineArray[0][2];
|
||||
const commonType = lineArray[0][3];
|
||||
|
||||
// Map points into a structured format
|
||||
const line = lineArray.map(([position, uuid]) => ({
|
||||
position,
|
||||
uuid,
|
||||
}));
|
||||
|
||||
// Create the final structured object
|
||||
return {
|
||||
layer: commonLayer,
|
||||
type: commonType,
|
||||
line,
|
||||
};
|
||||
}).filter((item) => item !== null); // Filter out invalid entries
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLineToArray(structuredObject: any) {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Destructure common properties
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
// Map points back to the original array format
|
||||
return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
export default function objectLinesToArray(structuredObjects: any): any {
|
||||
if (!Array.isArray(structuredObjects)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return structuredObjects.map((structuredObject) => {
|
||||
if (!structuredObject || !structuredObject.line) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { layer, type, line } = structuredObject;
|
||||
|
||||
return line.map(({ position, uuid }: any) => {
|
||||
const vector = new THREE.Vector3(position.x, position.y, position.z);
|
||||
return [vector, uuid, layer, type];
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function RemoveConnectedLines(
|
||||
DeletedPointUUID: Types.String,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
setDeletedLines: any,
|
||||
lines: Types.RefLines,
|
||||
): void {
|
||||
|
||||
////////// Check if any and how many lines are connected to the deleted point //////////
|
||||
|
||||
const removableLines: THREE.Mesh[] = [];
|
||||
const connectedpoints: string[] = [];
|
||||
|
||||
const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines
|
||||
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
|
||||
if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) {
|
||||
connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1);
|
||||
removableLines.push(line as THREE.Mesh);
|
||||
removedLinePoints.push(linePoints);
|
||||
}
|
||||
});
|
||||
|
||||
if (removableLines.length > 0) {
|
||||
removableLines.forEach((line) => {
|
||||
lines.current = lines.current.filter(item => item !== line.userData.linePoints);
|
||||
(<any>line.material).dispose();
|
||||
(<any>line.geometry).dispose();
|
||||
floorPlanGroupLine.current.remove(line);
|
||||
});
|
||||
}
|
||||
setDeletedLines(removedLinePoints)
|
||||
|
||||
////////// Check and Remove point that are no longer connected to any lines //////////
|
||||
|
||||
connectedpoints.forEach((pointUUID) => {
|
||||
let isConnected = false;
|
||||
floorPlanGroupLine.current.children.forEach((line) => {
|
||||
const linePoints = line.userData.linePoints as [number, string, number][];
|
||||
const uuid1 = linePoints[0][1];
|
||||
const uuid2 = linePoints[1][1];
|
||||
if (uuid1 === pointUUID || uuid2 === pointUUID) {
|
||||
isConnected = true;
|
||||
}
|
||||
});
|
||||
if (!isConnected) {
|
||||
floorPlanGroupPoint.current.children.forEach((point: any) => {
|
||||
if (point.uuid === pointUUID) {
|
||||
(<any>point.material).dispose();
|
||||
(<any>point.geometry).dispose();
|
||||
floorPlanGroupPoint.current.remove(point);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default RemoveConnectedLines;
|
||||
@@ -1,22 +0,0 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function removeReferenceLine(
|
||||
floorPlanGroup: Types.RefGroup,
|
||||
ReferenceLineMesh: Types.RefMesh,
|
||||
LineCreated: Types.RefBoolean,
|
||||
line: Types.RefLine
|
||||
): void {
|
||||
|
||||
////////// Removes Dangling reference line if the draw mode is ended or any other case //////////
|
||||
|
||||
line.current = [];
|
||||
if (ReferenceLineMesh.current) {
|
||||
(<any>ReferenceLineMesh.current.material).dispose();
|
||||
(<any>ReferenceLineMesh.current.geometry).dispose();
|
||||
floorPlanGroup.current.remove(ReferenceLineMesh.current);
|
||||
LineCreated.current = false;
|
||||
ReferenceLineMesh.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export default removeReferenceLine;
|
||||
@@ -1,151 +0,0 @@
|
||||
import * as THREE from "three";
|
||||
|
||||
import addLineToScene from "./addLineToScene";
|
||||
import addPointToScene from "../points/addPointToScene";
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import arrayLineToObject from "../lines/lineConvertions/arrayLineToObject";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { getUserData } from "../../../../functions/getUserData";
|
||||
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
|
||||
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
|
||||
|
||||
function splitLine(
|
||||
visibleIntersect: Types.IntersectionEvent,
|
||||
intersectionPoint: Types.Vector3,
|
||||
currentLayerPoint: Types.RefMeshArray,
|
||||
floorPlanGroupPoint: Types.RefGroup,
|
||||
dragPointControls: Types.RefDragControl,
|
||||
isSnappedUUID: Types.RefString,
|
||||
lines: Types.RefLines,
|
||||
setDeletedLines: any,
|
||||
floorPlanGroupLine: { current: THREE.Group },
|
||||
socket: Socket<any>,
|
||||
pointColor: Types.String,
|
||||
lineColor: Types.String,
|
||||
lineType: Types.String,
|
||||
projectId?: string,
|
||||
versionId?: string,
|
||||
): [Types.Line, Types.Line] {
|
||||
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
|
||||
|
||||
const { userId, organization, email } = getUserData();
|
||||
(visibleIntersect.object as any).material.dispose();
|
||||
(visibleIntersect.object as any).geometry.dispose();
|
||||
floorPlanGroupLine.current.remove(visibleIntersect.object);
|
||||
setDeletedLines([visibleIntersect.object.userData.linePoints]);
|
||||
|
||||
//REST
|
||||
|
||||
// deleteLineApi(
|
||||
// organization,
|
||||
// [
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
|
||||
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
|
||||
// ]
|
||||
// )
|
||||
|
||||
//SOCKET
|
||||
|
||||
const data = {
|
||||
organization,
|
||||
line: [
|
||||
{ uuid: visibleIntersect.object.userData.linePoints[0][1] },
|
||||
{ uuid: visibleIntersect.object.userData.linePoints[1][1] },
|
||||
],
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:delete", data);
|
||||
|
||||
const point = addPointToScene(
|
||||
intersectionPoint,
|
||||
pointColor,
|
||||
currentLayerPoint,
|
||||
floorPlanGroupPoint,
|
||||
dragPointControls,
|
||||
isSnappedUUID,
|
||||
lineType
|
||||
);
|
||||
|
||||
const oldLinePoints = visibleIntersect.object.userData.linePoints;
|
||||
lines.current = lines.current.filter((item) => item !== oldLinePoints);
|
||||
|
||||
const clickedPoint: Types.Point = [
|
||||
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
|
||||
point.uuid,
|
||||
oldLinePoints[0][2],
|
||||
lineType,
|
||||
];
|
||||
|
||||
const start = oldLinePoints[0];
|
||||
const end = oldLinePoints[1];
|
||||
|
||||
const newLine1: Types.Line = [start, clickedPoint];
|
||||
const newLine2: Types.Line = [clickedPoint, end];
|
||||
|
||||
const line1 = arrayLineToObject(newLine1);
|
||||
const line2 = arrayLineToObject(newLine2);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line1.layer!, line1.line!, line1.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input1 = {
|
||||
organization,
|
||||
layer: line1.layer,
|
||||
line: line1.line,
|
||||
type: line1.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input1);
|
||||
|
||||
//REST
|
||||
|
||||
// setLine(organization, line2.layer!, line2.line!, line2.type!);
|
||||
|
||||
//SOCKET
|
||||
|
||||
const input2 = {
|
||||
organization,
|
||||
layer: line2.layer,
|
||||
line: line2.line,
|
||||
type: line2.type,
|
||||
socketId: socket.id,
|
||||
versionId,
|
||||
projectId,
|
||||
userId,
|
||||
};
|
||||
|
||||
socket.emit("v1:Line:create", input2);
|
||||
|
||||
lines.current.push(newLine1, newLine2);
|
||||
|
||||
addLineToScene(
|
||||
newLine1[0][0],
|
||||
newLine1[1][0],
|
||||
lineColor,
|
||||
newLine1,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
addLineToScene(
|
||||
newLine2[0][0],
|
||||
newLine2[1][0],
|
||||
lineColor,
|
||||
newLine2,
|
||||
floorPlanGroupLine
|
||||
);
|
||||
|
||||
return [newLine1, newLine2];
|
||||
}
|
||||
|
||||
export default splitLine;
|
||||
@@ -1,42 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateDistanceText(
|
||||
scene: THREE.Scene,
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the Distance Texts of the lines that are affected during drag //////////
|
||||
|
||||
const DistanceGroup = scene.getObjectByName('Distance_Text') as THREE.Group;
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh;
|
||||
const linePoints = mesh.userData.linePoints;
|
||||
|
||||
if (linePoints) {
|
||||
const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1);
|
||||
const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2);
|
||||
|
||||
if (!DistanceGroup || !linePoints) {
|
||||
return
|
||||
}
|
||||
|
||||
DistanceGroup.children.forEach((text) => {
|
||||
const textMesh = text as THREE.Mesh;
|
||||
if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) {
|
||||
textMesh.position.set(position.x, 1, position.z);
|
||||
const className = `distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`;
|
||||
const element = document.getElementsByClassName(className)[0] as HTMLElement;
|
||||
if (element) {
|
||||
element.innerHTML = `${distance} m`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default updateDistanceText;
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
|
||||
function updateLines(
|
||||
floorPlanGroupLine: Types.RefGroup,
|
||||
affectedLines: Types.NumberArray
|
||||
): void {
|
||||
|
||||
////////// Updating the positions for the affected lines only based on the updated positions //////////
|
||||
|
||||
affectedLines.forEach((lineIndex) => {
|
||||
const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh;
|
||||
const linePoints = mesh.userData.linePoints as Types.Line;
|
||||
if (linePoints) {
|
||||
const newPositions = linePoints.map(([pos]) => pos);
|
||||
const newPath = new THREE.CatmullRomCurve3(newPositions);
|
||||
mesh.geometry.dispose();
|
||||
mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default updateLines;
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function updateLinesPositions(
|
||||
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 },
|
||||
lines: Types.RefLines
|
||||
): Types.NumberArray {
|
||||
|
||||
////////// Updating the lines position based on the dragged point's position //////////
|
||||
|
||||
const objectUUID = DragedPoint.uuid;
|
||||
const affectedLines: Types.NumberArray = [];
|
||||
|
||||
lines.current.forEach((line, index) => {
|
||||
let lineUpdated = false;
|
||||
line.forEach((point) => {
|
||||
const [position, uuid] = point;
|
||||
if (uuid === objectUUID) {
|
||||
position.x = DragedPoint.position.x;
|
||||
position.y = 0.01;
|
||||
position.z = DragedPoint.position.z;
|
||||
lineUpdated = true;
|
||||
}
|
||||
});
|
||||
if (lineUpdated) {
|
||||
affectedLines.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
return affectedLines;
|
||||
}
|
||||
|
||||
export default updateLinesPositions;
|
||||
@@ -1,18 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function vectorizeLinesCurrent(
|
||||
lines: Types.Lines
|
||||
): Types.Lines {
|
||||
|
||||
////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again //////////
|
||||
|
||||
return lines.map((line) => {
|
||||
const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],];
|
||||
const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],];
|
||||
return [p1, p2];
|
||||
});
|
||||
}
|
||||
|
||||
export default vectorizeLinesCurrent;
|
||||
@@ -1,54 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import updateReferencePolesheight from './updateReferencePolesheight';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addAndUpdateReferencePillar(
|
||||
raycaster: THREE.Raycaster,
|
||||
floorGroup: Types.RefGroup,
|
||||
referencePole: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Find Pillars position and scale based on the pointer interaction //////////
|
||||
|
||||
let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
|
||||
|
||||
if (intersected) {
|
||||
const intersectionPoint = intersected.point;
|
||||
raycaster.ray.origin.copy(intersectionPoint);
|
||||
raycaster.ray.direction.set(0, -1, 0);
|
||||
const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
|
||||
|
||||
let distance: Types.Number;
|
||||
|
||||
if (validIntersections.length > 1) {
|
||||
let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
|
||||
if (valid) {
|
||||
updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
|
||||
distance = intersected.point.distanceTo(belowPoint);
|
||||
if (distance > 3) {
|
||||
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (referencePole.current) {
|
||||
(<any>referencePole.current.material).dispose();
|
||||
(<any>referencePole.current.geometry).dispose();
|
||||
floorGroup.current.remove(referencePole.current);
|
||||
referencePole.current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default addAndUpdateReferencePillar;
|
||||
@@ -1,24 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function addPillar(
|
||||
referencePole: Types.RefMesh,
|
||||
floorGroup: Types.RefGroup
|
||||
): void {
|
||||
|
||||
////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
|
||||
|
||||
if (referencePole.current) {
|
||||
let pole: THREE.Mesh;
|
||||
const geometry = referencePole.current.userData.geometry.clone();
|
||||
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
|
||||
pole = new THREE.Mesh(geometry, material);
|
||||
pole.rotateX(Math.PI / 2);
|
||||
pole.name = "Pole";
|
||||
pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
|
||||
floorGroup.current.add(pole);
|
||||
}
|
||||
}
|
||||
|
||||
export default addPillar;
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function DeletableHoveredPillar(
|
||||
state: Types.ThreeState,
|
||||
floorGroup: Types.RefGroup,
|
||||
hoveredDeletablePillar: Types.RefMesh
|
||||
): void {
|
||||
|
||||
////////// Altering the color of the hovered Pillar during the Deletion time //////////
|
||||
|
||||
const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
|
||||
const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
|
||||
|
||||
if (poleIntersect) {
|
||||
if (poleIntersect.object.name !== "Pole") {
|
||||
return;
|
||||
}
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
|
||||
} else {
|
||||
if (hoveredDeletablePillar.current) {
|
||||
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
|
||||
hoveredDeletablePillar.current = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DeletableHoveredPillar;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user