From 8af4442a28ec7604b02aa9532d3e181b3131278f Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Wed, 21 May 2025 17:46:16 +0530 Subject: [PATCH 01/21] Refactor Dashboard components and styles for improved functionality and UI consistency --- .../layout/Dashboard/DashboardCard.tsx | 122 ++++++-- .../layout/Dashboard/DashboardHome.tsx | 12 +- .../layout/Dashboard/DashboardProjects.tsx | 281 +++++++++--------- .../layout/Dashboard/DashboardTrash.tsx | 214 +++++++------ .../layout/Dashboard/DashboardTutorial.tsx | 2 +- app/src/pages/Dashboard.tsx | 35 ++- app/src/styles/abstracts/variables.scss | 2 +- app/src/styles/pages/dashboard.scss | 180 +++++++++-- 8 files changed, 520 insertions(+), 328 deletions(-) diff --git a/app/src/components/layout/Dashboard/DashboardCard.tsx b/app/src/components/layout/Dashboard/DashboardCard.tsx index b6e818c..7adc59f 100644 --- a/app/src/components/layout/Dashboard/DashboardCard.tsx +++ b/app/src/components/layout/Dashboard/DashboardCard.tsx @@ -1,10 +1,11 @@ -import React from "react"; +import React, { useState, useRef } from "react"; import { KebabIcon } from "../../icons/ExportCommonIcons"; import img from "../../../assets/image/image.png"; import { useNavigate } from "react-router-dom"; import { useProjectName } from "../../../store/builder/store"; import { viewProject } from "../../../services/dashboard/viewProject"; import { getUserData } from "./functions/getUserData"; +import OuterClick from "../../../utils/outerClick"; interface DashBoardCardProps { projectName: string; @@ -21,58 +22,113 @@ const DashboardCard: React.FC = ({ projectId, handleRestoreProject, }) => { - let navigate = useNavigate(); + const navigate = useNavigate(); const { setProjectName } = useProjectName(); const { userId, organization, userName } = getUserData(); + const [isKebabOpen, setIsKebabOpen] = useState(false); - const handleKebabIconClick = async () => { - try { - if (handleRestoreProject) { - await handleRestoreProject(projectId); - } else if (handleDeleteProject) { - await handleDeleteProject(projectId); - } - } catch { } - }; + const kebabRef = useRef(null); const navigateToProject = async () => { try { const viewedProject = await viewProject(organization, projectId, userId); - console.log("Saved viewwdProject:", viewedProject); + console.log("Viewed project:", viewedProject); } catch (error) { - console.error("Error deleting project:", error); + console.error("Error opening project:", error); } setProjectName(projectName); navigate(`/${projectId}`); }; + const handleOptionClick = async (option: string) => { + switch (option) { + case "delete": + if (handleDeleteProject) { + await handleDeleteProject(projectId); + } + break; + case "restore": + if (handleRestoreProject) { + await handleRestoreProject(projectId); + } + break; + case "openInNewTab": + window.open(`/${projectId}`, "_blank"); + break; + case "rename": + // Add rename logic here + break; + case "duplicate": + // Add duplication logic here + break; + default: + break; + } + setIsKebabOpen(false); + }; + + OuterClick({ + contextClassName: ["kebab-wrapper", "kebab-options-wrapper"], + setMenuVisible: () => setIsKebabOpen(false), + }); return ( -
-
- {thumbnail ? : } -
-
-
-
{projectName}
-
24-12-2025
+
- + + {isKebabOpen && ( +
+ {["rename", "delete", "duplicate", "open in new tab"].map((option) => ( + + ))} +
+ )} + ); }; -export default DashboardCard; \ No newline at end of file +export default DashboardCard; diff --git a/app/src/components/layout/Dashboard/DashboardHome.tsx b/app/src/components/layout/Dashboard/DashboardHome.tsx index 98b8a5c..364d3f9 100644 --- a/app/src/components/layout/Dashboard/DashboardHome.tsx +++ b/app/src/components/layout/Dashboard/DashboardHome.tsx @@ -43,7 +43,11 @@ const DashboardHome: React.FC = () => { setIsSearchActive(false); return; } - const filterRecentProcess = await searchProject(organization, userId, inputValue); + const filterRecentProcess = await searchProject( + organization, + userId, + inputValue + ); setIsSearchActive(true); setRecentProjects(filterRecentProcess.message ? {} : filterRecentProcess); }; @@ -127,11 +131,13 @@ const DashboardHome: React.FC = () => {
-

Recent Projects

+

Recents

{renderProjects()}
); }; -export default DashboardHome; \ No newline at end of file +export default DashboardHome; + + diff --git a/app/src/components/layout/Dashboard/DashboardProjects.tsx b/app/src/components/layout/Dashboard/DashboardProjects.tsx index 8df8216..7afc7db 100644 --- a/app/src/components/layout/Dashboard/DashboardProjects.tsx +++ b/app/src/components/layout/Dashboard/DashboardProjects.tsx @@ -1,155 +1,154 @@ -import React, { useEffect, useState } from 'react'; -import DashboardNavBar from './DashboardNavBar'; -import DashboardCard from './DashboardCard'; -import { getAllProjects } from '../../../services/dashboard/getAllProjects'; -import { getUserData } from './functions/getUserData'; -import { searchProject } from '../../../services/dashboard/searchProjects'; -import { deleteProject } from '../../../services/dashboard/deleteProject'; -import { useSocketStore } from '../../../store/builder/store'; +import React, { useEffect, useState } from "react"; +import DashboardNavBar from "./DashboardNavBar"; +import DashboardCard from "./DashboardCard"; +import { getAllProjects } from "../../../services/dashboard/getAllProjects"; +import { getUserData } from "./functions/getUserData"; +import { searchProject } from "../../../services/dashboard/searchProjects"; +import { deleteProject } from "../../../services/dashboard/deleteProject"; +import { useSocketStore } from "../../../store/builder/store"; interface Project { - _id: string; - projectName: string; - thumbnail: string; - createdBy: string; - projectUuid?: string; + _id: string; + projectName: string; + thumbnail: string; + createdBy: string; + projectUuid?: string; } interface WorkspaceProjects { - [key: string]: Project[]; + [key: string]: Project[]; } const DashboardProjects: React.FC = () => { - const [workspaceProjects, setWorkspaceProjects] = useState({}); - const [isSearchActive, setIsSearchActive] = useState(false); - const [activeFolder, setActiveFolder] = useState("myProjects"); - const { dashBoardSocket } = useSocketStore(); - const { userId, organization } = getUserData(); + const [workspaceProjects, setWorkspaceProjects] = useState( + {} + ); + const [isSearchActive, setIsSearchActive] = useState(false); + const [activeFolder, setActiveFolder] = useState("myProjects"); + const { dashBoardSocket } = useSocketStore(); + const { userId, organization } = getUserData(); - const fetchAllProjects = async () => { - try { - const projects = await getAllProjects(userId, organization); + 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); - return; - } - if (!setWorkspaceProjects || !setIsSearchActive) return; + 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); + return; + } + if (!setWorkspaceProjects || !setIsSearchActive) return; - const searchedProject = await searchProject(organization, userId, inputValue); - setIsSearchActive(true); - setWorkspaceProjects(searchedProject.message ? {} : searchedProject); - }; - const handleDeleteProject = async (projectId: any) => { - try { - - const Organization = organization - // const deletedProject = await deleteProject( - // projectId, - // userId, - // Organization - // ); - const deleteProject = { - projectId, - organization: organization, - userId - } - if (dashBoardSocket) { - const handleResponse = (data: any) => { - console.log('Project add response:', data); - dashBoardSocket.off("v1-project:response:delete", handleResponse); // Clean up - }; - - dashBoardSocket.on("v1-project:response:delete", handleResponse); - - dashBoardSocket.emit("v1:project:delete", deleteProject); - } 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 renderProjects = () => { - if (activeFolder !== "myProjects") return null; - - const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]]; - - if (!projectList?.length) { - return
No projects found
; - } - - return projectList.map((project) => ( - - )); - }; - - useEffect(() => { - if (!isSearchActive) { - fetchAllProjects(); - } - }, [isSearchActive]); - - return ( -
- - -
-
-
setActiveFolder("myProjects")} - > - My Projects -
-
setActiveFolder("shared")} - > - Shared with me -
-
-
- {renderProjects()} -
-
-
+ const searchedProject = await searchProject( + organization, + userId, + inputValue ); + setIsSearchActive(true); + setWorkspaceProjects(searchedProject.message ? {} : searchedProject); + }; + const handleDeleteProject = async (projectId: any) => { + try { + const Organization = organization; + // const deletedProject = await deleteProject( + // projectId, + // userId, + // Organization + // ); + const deleteProject = { + projectId, + organization: organization, + userId, + }; + if (dashBoardSocket) { + const handleResponse = (data: any) => { + console.log("Project add response:", data); + dashBoardSocket.off("v1-project:response:delete", handleResponse); // Clean up + }; + + dashBoardSocket.on("v1-project:response:delete", handleResponse); + + dashBoardSocket.emit("v1:project:delete", deleteProject); + } 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 renderProjects = () => { + if (activeFolder !== "myProjects") return null; + + const projectList = workspaceProjects[Object.keys(workspaceProjects)[0]]; + + if (!projectList?.length) { + return
No projects found
; + } + + return projectList.map((project) => ( + + )); + }; + + useEffect(() => { + if (!isSearchActive) { + fetchAllProjects(); + } + }, [isSearchActive]); + + return ( +
+ + +
+
+ + +
+
{renderProjects()}
+
+
+ ); }; -export default DashboardProjects; \ No newline at end of file +export default DashboardProjects; diff --git a/app/src/components/layout/Dashboard/DashboardTrash.tsx b/app/src/components/layout/Dashboard/DashboardTrash.tsx index b66a05c..9d2cdf6 100644 --- a/app/src/components/layout/Dashboard/DashboardTrash.tsx +++ b/app/src/components/layout/Dashboard/DashboardTrash.tsx @@ -1,122 +1,120 @@ -import React, { useEffect, useState } from 'react'; -import { getTrash } from '../../../services/dashboard/getTrash'; -import DashboardCard from './DashboardCard'; -import DashboardNavBar from './DashboardNavBar'; -import { getUserData } from './functions/getUserData'; -import { trashSearchProject } from '../../../services/dashboard/trashSearchProject'; -import { restoreTrash } from '../../../services/dashboard/restoreTrash'; +import React, { useEffect, useState } from "react"; +import { getTrash } from "../../../services/dashboard/getTrash"; +import DashboardCard from "./DashboardCard"; +import DashboardNavBar from "./DashboardNavBar"; +import { getUserData } from "./functions/getUserData"; +import { trashSearchProject } from "../../../services/dashboard/trashSearchProject"; +import { restoreTrash } from "../../../services/dashboard/restoreTrash"; interface Project { - _id: string; - projectName: string; - thumbnail: string; - createdBy: string; - projectUuid?: string; + _id: string; + projectName: string; + thumbnail: string; + createdBy: string; + projectUuid?: string; } interface DiscardedProjects { - [key: string]: Project[]; + [key: string]: Project[]; } const DashboardTrash: React.FC = () => { - const [discardedProjects, setDiscardedProjects] = useState({}); - console.log('discardedProjects: ', discardedProjects); - const [isSearchActive, setIsSearchActive] = useState(false); - const { userId, organization } = getUserData(); + const [discardedProjects, setDiscardedProjects] = useState( + {} + ); + console.log("discardedProjects: ", discardedProjects); + const [isSearchActive, setIsSearchActive] = useState(false); + const { userId, organization } = getUserData(); - const fetchTrashProjects = async () => { - try { - const projects = await getTrash(organization); - console.log('organization: ', organization); - console.log('trashedprojects: ', projects); + const fetchTrashProjects = async () => { + try { + const projects = await getTrash(organization); + console.log("organization: ", organization); + console.log("trashedprojects: ", projects); - if (JSON.stringify(projects) !== JSON.stringify(discardedProjects)) { - setDiscardedProjects(projects); - } - } catch (error) { - console.error('Error fetching trash projects:', error); - } - }; - const handleTrashSearch = async ( - inputValue: string - ) => { - if (!inputValue.trim()) { - setIsSearchActive(false); - return; - } - if (!setDiscardedProjects || !setIsSearchActive) return; + if (JSON.stringify(projects) !== JSON.stringify(discardedProjects)) { + setDiscardedProjects(projects); + } + } catch (error) { + console.error("Error fetching trash projects:", error); + } + }; + const handleTrashSearch = async (inputValue: string) => { + if (!inputValue.trim()) { + setIsSearchActive(false); + return; + } + if (!setDiscardedProjects || !setIsSearchActive) return; - const filterTrashedProcess = await trashSearchProject(organization, userId, inputValue); - setIsSearchActive(true); - setDiscardedProjects(filterTrashedProcess.message ? {} : filterTrashedProcess); - }; - const handleRestoreProject = async (projectId: any) => { - try { - const Organization = organization; - const restoreProject = await restoreTrash( - Organization, - projectId - ); - - setDiscardedProjects((prevDiscardedProjects: DiscardedProjects) => { - // Check if TrashDatas exists and is an array - if (!Array.isArray(prevDiscardedProjects?.TrashDatas)) { - console.error('TrashDatas is not an array', prevDiscardedProjects); - return prevDiscardedProjects; - } - const updatedTrashDatas = prevDiscardedProjects.TrashDatas.filter( - (project) => project._id !== projectId - ); - return { - ...prevDiscardedProjects, - TrashDatas: updatedTrashDatas - }; - }); - setIsSearchActive(false) - } catch (error) { - console.error('Error deleting project:', error); - } - }; - const renderTrashProjects = () => { - const projectList = discardedProjects[Object.keys(discardedProjects)[0]]; - - if (!projectList?.length) { - return
No deleted projects found
; - } - - return projectList.map((project) => ( - - )); - }; - - useEffect(() => { - console.log('isSearchActive:trash ', isSearchActive); - if (!isSearchActive) { - fetchTrashProjects(); - } - }, [isSearchActive]); - - return ( -
- - -
-
-
- {renderTrashProjects()} -
-
-
+ const filterTrashedProcess = await trashSearchProject( + organization, + userId, + inputValue ); + setIsSearchActive(true); + setDiscardedProjects( + filterTrashedProcess.message ? {} : filterTrashedProcess + ); + }; + const handleRestoreProject = async (projectId: any) => { + try { + const Organization = organization; + const restoreProject = await restoreTrash(Organization, projectId); + + setDiscardedProjects((prevDiscardedProjects: DiscardedProjects) => { + // Check if TrashDatas exists and is an array + if (!Array.isArray(prevDiscardedProjects?.TrashDatas)) { + console.error("TrashDatas is not an array", prevDiscardedProjects); + return prevDiscardedProjects; + } + const updatedTrashDatas = prevDiscardedProjects.TrashDatas.filter( + (project) => project._id !== projectId + ); + return { + ...prevDiscardedProjects, + TrashDatas: updatedTrashDatas, + }; + }); + setIsSearchActive(false); + } catch (error) { + console.error("Error deleting project:", error); + } + }; + const renderTrashProjects = () => { + const projectList = discardedProjects[Object.keys(discardedProjects)[0]]; + + if (!projectList?.length) { + return
No deleted projects found
; + } + + return projectList.map((project) => ( + + )); + }; + + useEffect(() => { + console.log("isSearchActive:trash ", isSearchActive); + if (!isSearchActive) { + fetchTrashProjects(); + } + }, [isSearchActive]); + + return ( +
+ + +
+
+
{renderTrashProjects()}
+
+
+ ); }; -export default DashboardTrash; \ No newline at end of file +export default DashboardTrash; diff --git a/app/src/components/layout/Dashboard/DashboardTutorial.tsx b/app/src/components/layout/Dashboard/DashboardTutorial.tsx index 5e11ab8..2e96e29 100644 --- a/app/src/components/layout/Dashboard/DashboardTutorial.tsx +++ b/app/src/components/layout/Dashboard/DashboardTutorial.tsx @@ -49,7 +49,7 @@ const DashboardTutorial = () => { page="tutorial" /> -
+
{renderTrashProjects()} diff --git a/app/src/pages/Dashboard.tsx b/app/src/pages/Dashboard.tsx index 39afd94..a0593cd 100644 --- a/app/src/pages/Dashboard.tsx +++ b/app/src/pages/Dashboard.tsx @@ -1,15 +1,18 @@ -import React, { useEffect, useState } from 'react'; -import SidePannel from '../components/layout/Dashboard/SidePannel'; -import DashboardHome from '../components/layout/Dashboard/DashboardHome'; -import DashboardProjects from '../components/layout/Dashboard/DashboardProjects'; -import DashboardTrash from '../components/layout/Dashboard/DashboardTrash'; -import { useOrganization, useSocketStore, useUserName, useZones } from '../store/builder/store'; -import { getUserData } from '../components/layout/Dashboard/functions/getUserData'; -import DashboardTutorial from '../components/layout/Dashboard/DashboardTutorial'; - +import React, { useEffect, useState } from "react"; +import SidePannel from "../components/layout/Dashboard/SidePannel"; +import DashboardHome from "../components/layout/Dashboard/DashboardHome"; +import DashboardProjects from "../components/layout/Dashboard/DashboardProjects"; +import DashboardTrash from "../components/layout/Dashboard/DashboardTrash"; +import { + useOrganization, + useSocketStore, + useUserName, +} from "../store/builder/store"; +import { getUserData } from "../components/layout/Dashboard/functions/getUserData"; +import DashboardTutorial from "../components/layout/Dashboard/DashboardTutorial"; const Dashboard: React.FC = () => { - const [activeTab, setActiveTab] = useState('Home'); + const [activeTab, setActiveTab] = useState("Home"); const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); const { userId, organization, email, userName } = getUserData(); @@ -21,16 +24,16 @@ const Dashboard: React.FC = () => { setUserName(userName); } } - }, []) + }, []); return (
- {activeTab == 'Home' && } - {activeTab == 'Projects' && } - {activeTab == 'Trash' && } - {activeTab == 'Tutorials' && } + {activeTab == "Home" && } + {activeTab == "Projects" && } + {activeTab == "Trash" && } + {activeTab == "Tutorials" && }
); }; -export default Dashboard; \ No newline at end of file +export default Dashboard; diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index 0d50177..64978e1 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -192,4 +192,4 @@ $border-radius-large: 12px; $border-radius-circle: 50%; $border-radius-xlarge: 16px; $border-radius-extra-large: 20px; -$border-radius-xxx: 30px; +$border-radius-xxx: 30px; \ No newline at end of file diff --git a/app/src/styles/pages/dashboard.scss b/app/src/styles/pages/dashboard.scss index 38ac24a..d6d650e 100644 --- a/app/src/styles/pages/dashboard.scss +++ b/app/src/styles/pages/dashboard.scss @@ -5,19 +5,28 @@ height: 100vh; width: 100vw; display: flex; + padding: 27px 17px; + .side-pannel-container { padding: 32px; - min-width: 240px; - height: 100vh; + min-width: 280px; + height: 100%; display: flex; flex-direction: column; gap: 16px; - border-right: 1px solid var(--border-color); + // border-right: 1px solid var(--border-color); + background: var(--background-color); + backdrop-filter: blur(20px); + border-radius: 30px; + box-shadow: var(--box-shadow-medium); + .side-pannel-header { @include flex-space-between; + .user-container { @include flex-center; gap: 6px; + .user-profile { height: 32px; width: 32px; @@ -28,10 +37,12 @@ color: var(--primary-color); border-radius: #{$border-radius-circle}; } + .user-name { color: var(--accent-color); } } + .notifications-container { @include flex-center; height: 24px; @@ -39,82 +50,117 @@ cursor: pointer; } } + .new-project-button { padding: 12px 16px; cursor: not-allowed; - color: var(--accent-color); + color: var(--text-color); background: var(--background-color-secondary); - border-radius: #{$border-radius-large}; + border-radius: #{$border-radius-xxx}; } + .side-bar-content-container { display: flex; flex-direction: column; justify-content: space-between; height: 100%; + .side-bar-options-container { .option-list { display: flex; align-items: center; gap: 8px; - padding: 6px 10px; + padding: 8px 10px; margin: 4px 0; - border-radius: #{$border-radius-medium}; + border-radius: #{$border-radius-extra-large}; + cursor: pointer; + &:hover { background: var(--background-color-secondary); } } + .active { - color: var(--accent-color); + color: var(--text-button-color); font-weight: var(--font-weight-medium); - background: var(--highlight-accent-color); + background: var(--background-color-button); + &:hover { - background: var(--highlight-accent-color); + background: var(--background-color-button); } + } } } } + .dashboard-home-container { width: 100%; + padding-left: 18px; + .dashboard-navbar-container { margin-top: 28px; - padding: 8px 34px 8px 12px; + margin-bottom: 22px; @include flex-center; + .title { text-transform: capitalize; font-size: var(--font-size-large); width: 100%; } + .market-place-button { @include flex-center; gap: 6px; padding: 8px 14px; - background: var(--accent-gradient-color); + background: var(--background-color-button); white-space: nowrap; - border-radius: #{$border-radius-large}; - color: var(--primary-color); + border-radius: #{$border-radius-extra-large}; + + color: var(--text-button-color); } + .search-wrapper { width: 400px; } } + .container { margin: 22px 0; width: 100%; - padding: 0 12px; - .header { + height: calc(100% - 357px); + + + .header-wrapper { font-size: var(--font-size-large); + + .header { + color: var(--input-text-color); + padding: 6px 8px; + border-radius: #{$border-radius-extra-large}; + + &.active { + + background: var(--background-color-button); + color: var(--text-color); + } + } } + .cards-container { + height: 100%; display: flex; flex-wrap: wrap; position: relative; width: 100%; - padding: 8px; + padding-top: 18px; gap: 18px; + overflow: auto; } } } + + } .dashboard-card-container { @@ -123,11 +169,23 @@ min-width: 260px; position: relative; border: 1px solid var(--border-color); - border-radius: #{$border-radius-large}; + border-radius: #{$border-radius-extra-large}; overflow: hidden; + cursor: pointer; + overflow: visible; + position: relative; + + .dashboard-card-wrapper { + width: 100%; + height: 100%; + position: relative; + overflow: hidden; + } + .preview-container { height: 100%; width: 100%; + img { height: 100%; width: 100%; @@ -135,27 +193,38 @@ vertical-align: top; border: none; outline: none; + border-radius: #{$border-radius-extra-large}; } } + .project-details-container { @include flex-space-between; position: absolute; bottom: 0; width: 100%; - padding: 8px 16px; - background: var(--primary-color); - border-radius: #{$border-radius-large}; + padding: 13px 16px; + background: var(--background-color); + // backdrop-filter: blur(18px); + + border-radius: #{$border-radius-xlarge}; + transform: translateY(100%); + transition: transform 0.25s linear; + .project-details { .project-name { - margin-bottom: 2px; + margin-bottom: 7px; } + .project-data { - color: var(--accent-color); + color: var(--input-text-color); } } + .users-list-container { @include flex-center; gap: 6px; + position: relative; // Needed for absolute positioning of kebab-options-wrapper + .user-profile { height: 26px; width: 26px; @@ -165,8 +234,65 @@ color: var(--primary-color); border-radius: #{$border-radius-circle}; } + + .kebab { + padding: 10px; + @include flex-center; + transform: rotate(90deg); + } + } + + } + + + .kebab-options-wrapper { + position: absolute; + bottom: 40px; + right: 40px; + background: var(--background-color); + border: 1px solid var(--border-color); + border-radius: 8px; + z-index: 100; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + transform: translate(100%, 100%); + overflow: hidden; + display: none; + + .option { + padding: 8px 12px; + font-size: 14px; + text-align: left; + background: transparent; + border: none; + color: var(--text-color); + cursor: pointer; + transition: background 0.2s ease; + text-transform: capitalize; + + &:hover { + background-color: var(--background-color-secondary); + } } } + + + &:hover { + + + overflow: visible; + + .kebab-options-wrapper { + display: flex; + } + + .project-details-container { + transform: translateY(0); + } + } + + } .market-place-banner-container { @@ -174,13 +300,14 @@ height: 230px; overflow: hidden; position: relative; - padding: 0 24px; + img { height: 100%; width: 100%; object-fit: cover; border-radius: #{$border-radius-xxx}; } + .hero-text { position: absolute; left: 52px; @@ -191,6 +318,7 @@ color: #ffffff; text-transform: uppercase; } + .context { position: absolute; top: 20px; @@ -201,11 +329,13 @@ color: #ffffff; font-family: #{$font-roboto}; } + .arrow-context { position: absolute; bottom: 27px; right: 300px; } + .explore-button { position: absolute; top: 95px; @@ -218,4 +348,4 @@ font-family: #{$font-roboto}; cursor: pointer; } -} +} \ No newline at end of file -- 2.40.1 From b99981a6618cf70850217506801d4f21c4e16e9f Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 26 May 2025 10:20:35 +0530 Subject: [PATCH 02/21] Add newlines at the end of multiple service files for consistency --- app/src/services/dashboard/addedProject.ts | 1 + app/src/services/dashboard/createProject.ts | 2 +- app/src/services/dashboard/deleteProject.ts | 2 +- app/src/services/dashboard/getAllProjects.ts | 2 +- app/src/services/dashboard/getTrash.ts | 2 +- app/src/services/dashboard/projectTutorial.ts | 1 + app/src/services/dashboard/recentlyViewed.ts | 1 + app/src/services/dashboard/restoreTrash.ts | 1 + app/src/services/dashboard/searchProjects.ts | 2 +- app/src/services/dashboard/trashSearchProject.ts | 1 + app/src/services/dashboard/updateProject.ts | 2 +- app/src/services/dashboard/viewProject.ts | 1 + app/src/store/builder/store.ts | 2 +- 13 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/src/services/dashboard/addedProject.ts b/app/src/services/dashboard/addedProject.ts index e69de29..0519ecb 100644 --- a/app/src/services/dashboard/addedProject.ts +++ b/app/src/services/dashboard/addedProject.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/src/services/dashboard/createProject.ts b/app/src/services/dashboard/createProject.ts index 8d6fb98..4d4fbbb 100644 --- a/app/src/services/dashboard/createProject.ts +++ b/app/src/services/dashboard/createProject.ts @@ -1,7 +1,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; // let url_Backend_dwinzo = `http://192.168.0.102:5000`; // let url_Backend_dwinzo = `http://192.168.0.110:5000`; - + export const createProject = async ( projectUuid: string, userId: string, diff --git a/app/src/services/dashboard/deleteProject.ts b/app/src/services/dashboard/deleteProject.ts index b5449d9..0e36929 100644 --- a/app/src/services/dashboard/deleteProject.ts +++ b/app/src/services/dashboard/deleteProject.ts @@ -1,6 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; // let url_Backend_dwinzo = `http://192.168.0.102:5000`; - + export const deleteProject = async ( projectId: string, userId: string, diff --git a/app/src/services/dashboard/getAllProjects.ts b/app/src/services/dashboard/getAllProjects.ts index a43aecd..831f242 100644 --- a/app/src/services/dashboard/getAllProjects.ts +++ b/app/src/services/dashboard/getAllProjects.ts @@ -1,5 +1,5 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - + export const getAllProjects = async (userId: string, organization: string) => { try { const response = await fetch( diff --git a/app/src/services/dashboard/getTrash.ts b/app/src/services/dashboard/getTrash.ts index 76cd989..b3487e5 100644 --- a/app/src/services/dashboard/getTrash.ts +++ b/app/src/services/dashboard/getTrash.ts @@ -1,6 +1,6 @@ const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; // const url_Backend_dwinzo = `http://192.168.0.102:5000`; - + export const getTrash = async (organization: string) => { console.log("Organization:", organization); diff --git a/app/src/services/dashboard/projectTutorial.ts b/app/src/services/dashboard/projectTutorial.ts index e27f907..4b9dc7c 100644 --- a/app/src/services/dashboard/projectTutorial.ts +++ b/app/src/services/dashboard/projectTutorial.ts @@ -25,3 +25,4 @@ export const projectTutorial = async () => { } } }; + \ No newline at end of file diff --git a/app/src/services/dashboard/recentlyViewed.ts b/app/src/services/dashboard/recentlyViewed.ts index cfefa70..7a41169 100644 --- a/app/src/services/dashboard/recentlyViewed.ts +++ b/app/src/services/dashboard/recentlyViewed.ts @@ -22,3 +22,4 @@ export const recentlyViewed = async (organization: string, userId: string) => { throw new Error(error.message); } }; + \ No newline at end of file diff --git a/app/src/services/dashboard/restoreTrash.ts b/app/src/services/dashboard/restoreTrash.ts index 3e5adb2..a157779 100644 --- a/app/src/services/dashboard/restoreTrash.ts +++ b/app/src/services/dashboard/restoreTrash.ts @@ -24,3 +24,4 @@ export const restoreTrash = async (organization: string, projectId: string) => { throw new Error(error.message || "Unknown error"); } }; + \ No newline at end of file diff --git a/app/src/services/dashboard/searchProjects.ts b/app/src/services/dashboard/searchProjects.ts index 2740432..e7f858f 100644 --- a/app/src/services/dashboard/searchProjects.ts +++ b/app/src/services/dashboard/searchProjects.ts @@ -23,7 +23,7 @@ export const searchProject = async ( console.log("response: ", response); const result = await response.json(); console.log("result: ", result); - + return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/dashboard/trashSearchProject.ts b/app/src/services/dashboard/trashSearchProject.ts index 85732b2..06027e8 100644 --- a/app/src/services/dashboard/trashSearchProject.ts +++ b/app/src/services/dashboard/trashSearchProject.ts @@ -30,3 +30,4 @@ export const trashSearchProject = async ( } } }; + \ No newline at end of file diff --git a/app/src/services/dashboard/updateProject.ts b/app/src/services/dashboard/updateProject.ts index 8a1682c..14c81fe 100644 --- a/app/src/services/dashboard/updateProject.ts +++ b/app/src/services/dashboard/updateProject.ts @@ -28,7 +28,7 @@ export const updateProject = async ( body: JSON.stringify(body), } ); - + if (!response.ok) { throw new Error("Failed to clearPanel in the zone"); } diff --git a/app/src/services/dashboard/viewProject.ts b/app/src/services/dashboard/viewProject.ts index d2dff52..408aadd 100644 --- a/app/src/services/dashboard/viewProject.ts +++ b/app/src/services/dashboard/viewProject.ts @@ -26,3 +26,4 @@ export const viewProject = async ( throw new Error(error.message); } }; + \ No newline at end of file diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 527ee4d..b3c534d 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -10,7 +10,7 @@ export const useSocketStore = create((set: any, get: any) => ({ if (existingSocket) { return; } - + const socket = io( `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { -- 2.40.1 From 218f68b13a2c119f07cbd6de2054b83c765b88cc Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 26 May 2025 10:33:27 +0530 Subject: [PATCH 03/21] dxf loader --- app/package-lock.json | 69 +++++++-- app/package.json | 3 +- .../components/temporary/SelectFloorPlan.tsx | 82 +++++++++- app/src/modules/builder/builder.tsx | 5 +- app/src/modules/builder/dfx/LoadBlueprint.tsx | 38 +++++ .../dfx/functions/convertDxfToThree.ts | 65 ++++++++ .../functions/getWallPointsFromBlueprint.ts | 141 ++++++++++++++++++ app/src/modules/builder/findZoneName.tsx | 33 ---- .../modules/builder/groups/floorPlanGroup.tsx | 1 + app/src/store/builder/store.ts | 103 ++++++------- app/src/store/builder/uselayoutStore.ts | 2 +- app/src/types/builderTypes.d.ts | 78 ++++++---- 12 files changed, 489 insertions(+), 131 deletions(-) create mode 100644 app/src/modules/builder/dfx/LoadBlueprint.tsx create mode 100644 app/src/modules/builder/dfx/functions/convertDxfToThree.ts create mode 100644 app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts delete mode 100644 app/src/modules/builder/findZoneName.tsx diff --git a/app/package-lock.json b/app/package-lock.json index 3d5aea4..239990c 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -27,9 +27,11 @@ "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", "chartjs-plugin-annotation": "^3.1.0", + "dxf-parser": "^1.1.2", "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", + "immer": "^9.0.21", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2021,7 +2023,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2033,7 +2035,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4136,6 +4138,25 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4247,25 +4268,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9019,7 +9040,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9896,7 +9917,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -10067,6 +10088,14 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, + "node_modules/dxf-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/dxf-parser/-/dxf-parser-1.1.2.tgz", + "integrity": "sha512-GPTumUvRkounlIazLIyJMmTWt+nlg+ksS0Hdm8jWvejmZKBTz6gvHTam76wRm4PQMma5sgKLThblQyeIJcH79Q==", + "dependencies": { + "loglevel": "^1.7.1" + } + }, "node_modules/earcut": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", @@ -15181,6 +15210,18 @@ "node": ">=8" } }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -15259,7 +15300,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20727,7 +20768,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20770,7 +20811,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20782,7 +20823,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21278,7 +21319,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22337,7 +22378,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/package.json b/app/package.json index 66158c0..f3fc217 100644 --- a/app/package.json +++ b/app/package.json @@ -22,10 +22,11 @@ "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", "chartjs-plugin-annotation": "^3.1.0", + "dxf-parser": "^1.1.2", "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", - "immer": "^10.1.1", + "immer": "^9.0.21", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", diff --git a/app/src/components/temporary/SelectFloorPlan.tsx b/app/src/components/temporary/SelectFloorPlan.tsx index 7a95e8e..8f16006 100644 --- a/app/src/components/temporary/SelectFloorPlan.tsx +++ b/app/src/components/temporary/SelectFloorPlan.tsx @@ -1,8 +1,53 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import useLayoutStore from "../../store/builder/uselayoutStore"; +import { useDfxUpload } from "../../store/builder/store"; +import DxfParser from "dxf-parser"; +import { Box3, BufferGeometry, MathUtils, Vector3 } from "three"; +import { getWallPointsFromBlueprint } from "../../modules/builder/dfx/functions/getWallPointsFromBlueprint"; +import { convertDXFToThree } from "../../modules/builder/dfx/functions/convertDxfToThree"; +// Define types for DXF entities and geometries + const SelectFloorPlan: React.FC = () => { const { currentLayout, setLayout } = useLayoutStore(); + const { setDfxUploaded, setDfxGenerate } = useDfxUpload(); + + const [parsedFile, setParsedFile] = useState(); + const [generate, setGenerate] = useState(false); + + const handleFileUpload = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file || !file.name.endsWith(".dxf")) { + alert("Please upload a valid .dxf file."); + return; + } + + const reader = new FileReader(); + + reader.onload = async (e) => { + const dxfContent = e.target?.result as string; + + try { + const parser = new DxfParser(); + const parsedData = parser.parse(dxfContent) as DXFData; + const geometries = convertDXFToThree(parsedData); + + setParsedFile(parsedData); + setDfxUploaded(geometries); + + } catch (error) { + echo.error("Failed to import your .dxf file") + } + }; + + reader.readAsText(file); + }; + + useEffect(() => { + if (parsedFile !== undefined) + getWallPointsFromBlueprint({ parsedData: parsedFile, setDfxGenerate }) + }, [generate]) + return (
Preset Layouts @@ -23,9 +68,42 @@ const SelectFloorPlan: React.FC = () => { > Preset 2 + + + +
-
+
); }; export default SelectFloorPlan; + + + + + diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 96894fe..82c93ba 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -49,7 +49,7 @@ import CalculateAreaGroup from "./groups/calculateAreaGroup"; import LayoutImage from "./layout/layoutImage"; import AssetsGroup from "./assetGroup/assetsGroup"; import { Bvh } from "@react-three/drei"; -import FindZoneName from "./findZoneName"; +import DxfFile from "./dfx/LoadBlueprint"; export default function Builder() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -312,9 +312,10 @@ export default function Builder() { - + + diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx new file mode 100644 index 0000000..9be72dc --- /dev/null +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -0,0 +1,38 @@ +import { useEffect } from 'react'; +import { useDfxUpload, useToggleView } 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'; + +const DxfFile = ({ floorPlanGroupPoint, currentLayerPoint, dragPointControls, floorPlanGroupLine, lines, setUpdateScene }: any) => { + const { dfxuploaded, dfxWallGenerate } = useDfxUpload(); + const { toggleView } = useToggleView(); + + useEffect(() => { + if (dfxWallGenerate && dragPointControls && floorPlanGroupPoint && currentLayerPoint && floorPlanGroupLine) { + lines.current = dfxWallGenerate; + loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls); + loadInitialLine(floorPlanGroupLine, lines); + setUpdateScene(true); + } + }, [lines, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls, dfxWallGenerate]) + + return ( + <> + {dfxuploaded && dfxuploaded.length > 0 && toggleView && dfxuploaded?.map((geometry: any, index: any) => ( + + + + + + ))} + + ); +} + +export default DxfFile; diff --git a/app/src/modules/builder/dfx/functions/convertDxfToThree.ts b/app/src/modules/builder/dfx/functions/convertDxfToThree.ts new file mode 100644 index 0000000..7bf2634 --- /dev/null +++ b/app/src/modules/builder/dfx/functions/convertDxfToThree.ts @@ -0,0 +1,65 @@ +import { BufferGeometry, Vector3 } from "three"; + +export const convertDXFToThree = (dxfData: DXFData): BufferGeometry[] => { + const geometries: BufferGeometry[] = []; + const UNIT = 1000; + if (dxfData.entities) { + dxfData.entities.forEach((entity) => { + // LINE + if (entity.type === "LINE" && entity.vertices) { + const points = [ + new Vector3(entity.vertices[0].x, entity.vertices[0].y, 0), + new Vector3(entity.vertices[1].x, entity.vertices[1].y, 0), + ]; + const geometry = new BufferGeometry().setFromPoints(points); + geometry.scale(1 / UNIT, 1 / UNIT, 1 / UNIT); + geometries.push(geometry); + } + + // LWPOLYLINE + else if (entity.type === "LWPOLYLINE" && entity.vertices) { + const points: Vector3[] = entity.vertices.map( + (v: any) => new Vector3(v.x, v.y, 0) + ); + + for (let i = 0; i < points.length - 1; i++) { + const segment = [points[i], points[i + 1]]; + const geometry = new BufferGeometry().setFromPoints(segment); + geometry.scale(1 / UNIT, 1 / UNIT, 1 / UNIT); + geometries.push(geometry); + } + } + + // ARC + else if ( + entity.type === "ARC" && + entity.center && + entity.radius !== undefined + ) { + const { center, radius, startAngle, endAngle } = entity; + if ( + center === undefined || + radius === undefined || + startAngle === undefined || + endAngle === undefined + ) + return; + const numSegments = 32; + const points: Vector3[] = []; + + for (let i = 0; i <= numSegments; i++) { + const t = i / numSegments; + const angle = startAngle + t * (endAngle - startAngle); // linear interpolation + const x = center.x + radius * Math.cos(angle); + const y = center.y + radius * Math.sin(angle); + points.push(new Vector3(x, y, 0)); + } + + const geometry = new BufferGeometry().setFromPoints(points); + geometry.scale(1 / UNIT, 1 / UNIT, 1 / UNIT); + geometries.push(geometry); + } + }); + } + return geometries; +}; diff --git a/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts b/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts new file mode 100644 index 0000000..72057dd --- /dev/null +++ b/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts @@ -0,0 +1,141 @@ +import { MathUtils, Vector3, BufferGeometry } from "three"; + +interface Props { + parsedData: DXFData; + setDfxGenerate: (walls: WallLineVertex[][]) => void; +} + +export function getWallPointsFromBlueprint({ + parsedData, + setDfxGenerate, +}: Props) { + if (!parsedData.entities) return; + + const unit = 1000; // Convert mm to meters + + const wallVertex: WallLineVertex[][] = []; + + parsedData.entities.forEach((entity: DXFEntity) => { + if (entity.type === "LINE" && entity.vertices) { + const startVec = new Vector3( + entity.vertices[0].x / unit, + 0.01, + -entity.vertices[0].y / unit + ); + const endVec = new Vector3( + entity.vertices[1].x / unit, + 0.01, + -entity.vertices[1].y / unit + ); + + const existingStart = wallVertex + .flat() + .find((v) => v[0].equals(startVec)); + const startPoint: WallLineVertex = existingStart || [ + startVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + const existingEnd = wallVertex.flat().find((v) => v[0].equals(endVec)); + const endPoint: WallLineVertex = existingEnd || [ + endVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + wallVertex.push([startPoint, endPoint]); + } else if (entity.type === "LWPOLYLINE" && entity.vertices) { + let firstPoint: WallLineVertex | undefined; + + for (let i = 0; i < entity.vertices.length - 1; i++) { + const startVec = new Vector3( + entity.vertices[i].x / unit, + 0.01, + -entity.vertices[i].y / unit + ); + const endVec = new Vector3( + entity.vertices[i + 1].x / unit, + 0.01, + -entity.vertices[i + 1].y / unit + ); + + const existingStart = wallVertex + .flat() + .find((v) => v[0].equals(startVec)); + const startPoint: WallLineVertex = existingStart || [ + startVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + const existingEnd = wallVertex.flat().find((v) => v[0].equals(endVec)); + const endPoint: WallLineVertex = existingEnd || [ + endVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + wallVertex.push([startPoint, endPoint]); + + if (i === 0) firstPoint = startPoint; + if (i === entity.vertices.length - 2 && firstPoint) + wallVertex.push([endPoint, firstPoint]); + } + } else if (entity.type === "ARC") { + const { center, radius, startAngle, endAngle } = entity; + if ( + !center || + radius === undefined || + startAngle === undefined || + endAngle === undefined + ) + return; + + const numSegments = 16; + const angleStep = (endAngle - startAngle) / numSegments; + + const arcPoints: Vector3[] = []; + + for (let i = 0; i <= numSegments; i++) { + const angle = startAngle + i * angleStep; + const x = center.x + radius * Math.cos(angle); + const y = -center.y + radius * Math.sin(angle); + arcPoints.push(new Vector3(x / unit, 0.01, y / unit)); + } + + for (let i = 0; i < arcPoints.length - 1; i++) { + const startVec = arcPoints[i]; + const endVec = arcPoints[i + 1]; + + const existingStart = wallVertex + .flat() + .find((v) => v[0].equals(startVec)); + const startPoint: WallLineVertex = existingStart || [ + startVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + const existingEnd = wallVertex.flat().find((v) => v[0].equals(endVec)); + const endPoint: WallLineVertex = existingEnd || [ + endVec, + MathUtils.generateUUID(), + 1, + "WallLine", + ]; + + wallVertex.push([startPoint, endPoint]); + } + } else { + console.error("Unsupported entity type:", entity.type); + } + }); + + setDfxGenerate(wallVertex); +} diff --git a/app/src/modules/builder/findZoneName.tsx b/app/src/modules/builder/findZoneName.tsx deleted file mode 100644 index 1f8966c..0000000 --- a/app/src/modules/builder/findZoneName.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { useToggleView, useZones } from '../../store/builder/store'; -import { Html } from '@react-three/drei'; - -const FindZoneName = () => { - const { zones } = useZones(); - const { toggleView } = useToggleView(); - return ( - <> - {!toggleView && zones?.map((zone: any) => ( - - {zone.zoneName} - - ))} - - ); -} - -export default FindZoneName; diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index a8832f2..6a9e50f 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -50,6 +50,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin getLines(organization).then((data) => { const Lines: Types.Lines = objectLinesToArray(data); + console.log('Lines: ', Lines); // const data = localStorage.getItem("Lines"); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index f05a1b2..f1f4133 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -459,88 +459,91 @@ interface ShortcutStore { } export const useShortcutStore = create((set) => ({ - showShortcuts: false, - setShowShortcuts: (value) => set({ showShortcuts: value }), - toggleShortcuts: () => - set((state) => ({ showShortcuts: !state.showShortcuts })), + showShortcuts: false, + setShowShortcuts: (value) => set({ showShortcuts: value }), + toggleShortcuts: () => + set((state) => ({ showShortcuts: !state.showShortcuts })), })); export const useMachineCount = create((set: any) => ({ - machineCount: 0, - setMachineCount: (x: any) => set({ machineCount: x }), + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), })); export const useMachineUptime = create((set: any) => ({ - machineActiveTime: 0, - setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), })); export const useMaterialCycle = create((set: any) => ({ - materialCycleTime: 0, - setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), })); export const useThroughPutData = create((set: any) => ({ - throughputData: 0, - setThroughputData: (x: any) => set({ throughputData: x }), + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), })); export const useProductionCapacityData = create((set: any) => ({ - productionCapacityData: 0, - setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), })); export const useProcessBar = create((set: any) => ({ - processBar: [], - setProcessBar: (x: any) => set({ processBar: x }), + processBar: [], + setProcessBar: (x: any) => set({ processBar: x }), +})); +export const useDfxUpload = create((set: any) => ({ + dfxuploaded: [], + dfxWallGenerate: [], + setDfxUploaded: (x: any) => set({ dfxuploaded: x }), + setDfxGenerate: (x: any) => set({ dfxWallGenerate: x }), })); - type InputValuesStore = { - inputValues: Record; - setInputValues: (values: Record) => void; - updateInputValue: (label: string, value: string) => void; // <- New + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New }; export const useInputValues = create((set) => ({ - inputValues: {}, - setInputValues: (values) => set({ inputValues: values }), - updateInputValue: (label, value) => - set((state) => ({ - inputValues: { - ...state.inputValues, - [label]: value, - }, - })), + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), })); export interface ROISummaryData { - productName: string; - roiPercentage: number; - paybackPeriod: number; - totalCost: number; - revenueGenerated: number; - netProfit: number; - netLoss: number; + productName: string; + roiPercentage: number; + paybackPeriod: number; + totalCost: number; + revenueGenerated: number; + netProfit: number; + netLoss: number; } interface ROISummaryStore { - roiSummary: ROISummaryData; - setRoiSummaryData: (values: ROISummaryData) => void; + roiSummary: ROISummaryData; + setRoiSummaryData: (values: ROISummaryData) => void; } export const useROISummaryData = create((set) => ({ - roiSummary: { - productName: "", - roiPercentage: 0, - paybackPeriod: 0, - totalCost: 0, - revenueGenerated: 0, - netProfit: 0, - netLoss: 0, - }, - setRoiSummaryData: (values) => set({ roiSummary: values }), + roiSummary: { + productName: "", + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }, + setRoiSummaryData: (values) => set({ roiSummary: values }), })); - - interface CompareStore { comparePopUp: boolean; setComparePopUp: (value: boolean) => void; diff --git a/app/src/store/builder/uselayoutStore.ts b/app/src/store/builder/uselayoutStore.ts index acaeb50..a8de713 100644 --- a/app/src/store/builder/uselayoutStore.ts +++ b/app/src/store/builder/uselayoutStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; -type Layout = null | 'layout1' | 'layout2'; +type Layout = null | 'layout1' | 'layout2' ; type LayoutState = { currentLayout: Layout; diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index adfdc78..3c5bdfb 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -1,31 +1,53 @@ interface Asset { - modelUuid: string; - modelName: string; - assetId: string; - position: [number, number, number]; - rotation: [number, number, number]; - isLocked: boolean; - isCollidable: boolean; - isVisible: boolean; - opacity: number; - animations?: string[]; - animationState?: { - current: string; - playing: boolean; + modelUuid: string; + modelName: string; + assetId: string; + position: [number, number, number]; + rotation: [number, number, number]; + isLocked: boolean; + isCollidable: boolean; + isVisible: boolean; + opacity: number; + animations?: string[]; + animationState?: { + current: string; + playing: boolean; + }; + eventData?: { + type: string; + point?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; }; - eventData?: { - type: string; - point?: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - } - points?: { - uuid: string; - position: [number, number, number]; - rotation: [number, number, number]; - }[]; - } -}; + points?: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + }[]; + }; +} -type Assets = Asset[]; \ No newline at end of file +type Assets = Asset[]; + +// DXF Entity Schema + +interface DXFEntity { + type: string; + vertices?: { x: number; y: number }[]; + center?: { x: number; y: number; z: number }; + radius?: number; + startAngle?: number; + endAngle?: number; +} + +interface DXFData { + entities?: DXFEntity[]; +} + +type WallLineVertex = [ + Vector3, + string, // uuid + number, + string // "WallLine" +]; -- 2.40.1 From b76213f49f2d37e58096a02208d134c8b861d1f2 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 26 May 2025 17:58:46 +0530 Subject: [PATCH 04/21] Update environment variables, add fingerprinting, and refactor API endpoints - Changed server socket and REST API base URLs in .env file. - Added FingerprintJS dependencies to package.json and package-lock.json. - Implemented fingerprint generation in UserAuth component. - Updated API endpoints from v1 to v2 in various service files. - Refactored API calls to include authorization tokens. - Commented out console log statements for cleaner production code. --- app/.env | 6 +- app/package-lock.json | 107 +++++++++++++++--- app/package.json | 2 + .../layout/Dashboard/DashboardHome.tsx | 1 + .../properties/ZoneProperties.tsx | 2 +- app/src/components/ui/list/List.tsx | 2 +- .../visualization/zone/DisplayZone.tsx | 2 +- app/src/pages/UserAuth.tsx | 56 ++++++--- app/src/services/dashboard/createProject.ts | 24 ++-- app/src/services/dashboard/deleteProject.ts | 5 +- app/src/services/dashboard/getAllProjects.ts | 5 +- app/src/services/dashboard/getTrash.ts | 6 +- app/src/services/dashboard/projectTutorial.ts | 2 +- app/src/services/dashboard/recentlyViewed.ts | 7 +- app/src/services/dashboard/restoreTrash.ts | 7 +- app/src/services/dashboard/searchProjects.ts | 9 +- .../services/dashboard/trashSearchProject.ts | 6 +- app/src/services/dashboard/updateProject.ts | 5 +- app/src/services/dashboard/viewProject.ts | 12 +- .../assest/assets/getAssetImages.ts | 4 +- .../factoryBuilder/signInSignUp/signInApi.ts | 17 +-- .../factoryBuilder/signInSignUp/signUpApi.ts | 13 +-- 22 files changed, 206 insertions(+), 94 deletions(-) diff --git a/app/.env b/app/.env index 9116020..d923958 100644 --- a/app/.env +++ b/app/.env @@ -2,12 +2,12 @@ PORT=8200 # Base URL for the server socket API, used for real-time communication (e.g., WebSockets). -REACT_APP_SERVER_SOCKET_API_BASE_URL=192.168.0.110:8000 +REACT_APP_SERVER_SOCKET_API_BASE_URL=192.168.0.102:8000 # REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 # Base URL for the server REST API, used for HTTP requests to the backend server. -REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.110:5000 -# REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.102:5000 +# REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.110:5000 +REACT_APP_SERVER_REST_API_BASE_URL=192.168.0.102:5000 # REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 # Base URL for the server marketplace, used for market place model blob. diff --git a/app/package-lock.json b/app/package-lock.json index 3d5aea4..7e7ebe1 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", + "@fingerprintjs/fingerprintjs": "^4.6.2", + "@fingerprintjs/fingerprintjs-pro-react": "^2.6.3", "@react-three/csg": "^3.2.0", "@react-three/drei": "^9.113.0", "@react-three/fiber": "^8.17.7", @@ -30,6 +32,7 @@ "glob": "^11.0.0", "gsap": "^3.12.5", "html2canvas": "^1.4.1", + "immer": "^10.1.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2021,7 +2024,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2033,7 +2036,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -2535,6 +2538,45 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fingerprintjs/fingerprintjs": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.6.2.tgz", + "integrity": "sha512-g8mXuqcFKbgH2CZKwPfVtsUJDHyvcgIABQI7Y0tzWEFXpGxJaXuAuzlifT2oTakjDBLTK4Gaa9/5PERDhqUjtw==", + "license": "BUSL-1.1", + "dependencies": { + "tslib": "^2.4.1" + } + }, + "node_modules/@fingerprintjs/fingerprintjs-pro": { + "version": "3.11.10", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.11.10.tgz", + "integrity": "sha512-zuQWT0YQLT0T//KcjEnyn4YBPlxXuXCtPiwEt2eTv03I/k2m370X+pCOfgU26AEjkmPrhCE77FLpRnm0IwiWrg==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "tslib": "^2.4.1" + } + }, + "node_modules/@fingerprintjs/fingerprintjs-pro-react": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.6.3.tgz", + "integrity": "sha512-/axCq/cfjZkIM+WFZM/05FQvqtNfdKbIFKU6b2yrwPKlgT8BqWkAq8XvFX6JCPlq8/udVLJjFEDCK+1JQh1L6g==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.1", + "fast-deep-equal": "3.1.3" + } + }, + "node_modules/@fingerprintjs/fingerprintjs-pro-spa": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.2.tgz", + "integrity": "sha512-s1YGsx1XQLmjU+av4UrUHNxyzwPHyZRB0GXJQFOJK8ZHCYc2SNukxnJmZA++bNBa8twU3wW+QgSJhA4Prjnd0g==", + "license": "MIT", + "dependencies": { + "@fingerprintjs/fingerprintjs-pro": "^3.11.0", + "tslib": "^2.7.0" + } + }, "node_modules/@floating-ui/core": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", @@ -4136,6 +4178,26 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4247,25 +4309,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -9019,7 +9081,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9896,7 +9958,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -12726,9 +12788,10 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immer": { - "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -15259,7 +15322,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -17990,6 +18053,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/react-dev-utils/node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/react-dev-utils/node_modules/loader-utils": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", @@ -20727,7 +20800,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20770,7 +20843,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20782,7 +20855,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21278,7 +21351,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22337,7 +22410,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/package.json b/app/package.json index 66158c0..2efffdb 100644 --- a/app/package.json +++ b/app/package.json @@ -5,6 +5,8 @@ "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", + "@fingerprintjs/fingerprintjs": "^4.6.2", + "@fingerprintjs/fingerprintjs-pro-react": "^2.6.3", "@react-three/csg": "^3.2.0", "@react-three/drei": "^9.113.0", "@react-three/fiber": "^8.17.7", diff --git a/app/src/components/layout/Dashboard/DashboardHome.tsx b/app/src/components/layout/Dashboard/DashboardHome.tsx index 364d3f9..f459b1b 100644 --- a/app/src/components/layout/Dashboard/DashboardHome.tsx +++ b/app/src/components/layout/Dashboard/DashboardHome.tsx @@ -29,6 +29,7 @@ const DashboardHome: React.FC = () => { const fetchRecentProjects = async () => { try { const projects = await recentlyViewed(organization, userId); + console.log('RecentlyViewed: ', projects); if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) { setRecentProjects(projects); diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 31c7761..e116c15 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -57,7 +57,7 @@ const ZoneProperties: React.FC = () => { }; // Call your API to update the zone let response = await zoneCameraUpdate(zonesdata, organization); - console.log("response: ", response); + // console.log("response: ", response); if (response.message === "updated successfully") { setZones((prevZones: any[]) => prevZones.map((zone) => diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index 860bae1..561007b 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -134,7 +134,7 @@ const List: React.FC = ({ items = [], remove }) => { zoneAssetId.id, newName ); - console.log("response: ", response); + // console.log("response: ", response); setFloorItems((prevFloorItems: any[]) => prevFloorItems.map((floorItems) => floorItems.modelUuid === zoneAssetId.id diff --git a/app/src/modules/visualization/zone/DisplayZone.tsx b/app/src/modules/visualization/zone/DisplayZone.tsx index d850db4..a3c21a3 100644 --- a/app/src/modules/visualization/zone/DisplayZone.tsx +++ b/app/src/modules/visualization/zone/DisplayZone.tsx @@ -174,7 +174,7 @@ const DisplayZone: React.FC = ({ const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; let response = await getSelect2dZoneData(zoneId, organization); - console.log("response: ", response); + // console.log("response: ", response); let res = await getFloatingZoneData(zoneId, organization); console.log("res: ", res); diff --git a/app/src/pages/UserAuth.tsx b/app/src/pages/UserAuth.tsx index 90b8e2c..8b4e7a6 100644 --- a/app/src/pages/UserAuth.tsx +++ b/app/src/pages/UserAuth.tsx @@ -1,4 +1,4 @@ -import React, { useState, FormEvent } from "react"; +import React, { useState, FormEvent, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { LogoIconLarge } from "../components/icons/Logo"; import { EyeIcon } from "../components/icons/ExportCommonIcons"; @@ -9,6 +9,7 @@ import { } from "../store/builder/store"; import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi"; import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi"; +import FingerprintJS from "@fingerprintjs/fingerprintjs"; const UserAuth: React.FC = () => { const [email, setEmail] = useState(""); @@ -19,33 +20,62 @@ const UserAuth: React.FC = () => { const { userName, setUserName } = useUserName(); const { setOrganization } = useOrganization(); const { setLoadingProgress } = useLoadingProgress(); + const [fingerprint, setFingerprint] = useState(""); const navigate = useNavigate(); + const initializeFingerprint = async () => { + const fp = await FingerprintJS.load(); + const result = await fp.get(); + setFingerprint(result.visitorId); // Set the fingerprint + }; + + useEffect(() => { + initializeFingerprint(); + }, []) + + const handleLogin = async (e: FormEvent) => { e.preventDefault(); - const organization = email.split("@")[1].split(".")[0]; - console.log('email, password, organization: ', email, password, organization); + try { - const res = await signInApi(email, password, organization); - - - if (res.message === "login successfull") { + const res = await signInApi(email, password, organization, fingerprint); + if (res.message.message === "login successfull") { setError(""); setOrganization(organization); - setUserName(res.name); - console.log(' res.userId: ', res.userId); - localStorage.setItem("userId", res.userId); - localStorage.setItem("email", res.email); - localStorage.setItem("userName", res.name); - if (res.isShare) { + setUserName(res.message.name); + // console.log(' res.userId: ', res.message.userId); + localStorage.setItem("userId", res.message.userId); + localStorage.setItem("email", res.message.email); + localStorage.setItem("userName", res.message.name); + localStorage.setItem("token", res.message.token); + localStorage.setItem("refreshToken", res.message.refreshToken); + + if (res.message.isShare) { setLoadingProgress(1); // navigate("/Project"); navigate("/Dashboard"); } } else if (res.message === "User Not Found!!! Kindly signup...") { setError("Account not found"); + } else if (res.message === "Already LoggedIn on another browser....Please logout!!!") { + setError("Already logged in on another browser. Please logout first."); + navigate("/"); + setError("") + // setError(""); + // setOrganization(organization); + // setUserName(res.ForceLogoutData.userName); + // console.log(' res.userId: ', res.ForceLogoutData.userId); + // localStorage.setItem("userId", res.ForceLogoutData.userId); + // localStorage.setItem("email", res.ForceLogoutData.Email); + // localStorage.setItem("userName", res.ForceLogoutData.userName); + // localStorage.setItem("token", res.ForceLogoutData.token); + // localStorage.setItem("refreshToken", res.ForceLogoutData.refreshToken); + // if (res.ForceLogoutData.isShare) { + // setLoadingProgress(1); + // navigate("/Dashboard"); + // } } } catch (error) { echo.error("Login failed"); diff --git a/app/src/services/dashboard/createProject.ts b/app/src/services/dashboard/createProject.ts index 4d4fbbb..2af5639 100644 --- a/app/src/services/dashboard/createProject.ts +++ b/app/src/services/dashboard/createProject.ts @@ -1,25 +1,17 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; -// let url_Backend_dwinzo = `http://192.168.0.110:5000`; - -export const createProject = async ( - projectUuid: string, - userId: string, - thumbnail: string, - organization: string -) => { + + +export const createProject = async (projectUuid: string, userId: string, thumbnail: string, organization: string) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/upsertProject`, { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/upsertProject`, { method: "POST", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, - body: JSON.stringify({ - projectUuid, - userId, - thumbnail, - organization, - }), + body: JSON.stringify({ projectUuid, userId, thumbnail, organization, }), }); if (!response.ok) { diff --git a/app/src/services/dashboard/deleteProject.ts b/app/src/services/dashboard/deleteProject.ts index 0e36929..be8abea 100644 --- a/app/src/services/dashboard/deleteProject.ts +++ b/app/src/services/dashboard/deleteProject.ts @@ -8,11 +8,14 @@ export const deleteProject = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1//Project/archive/${projectId}`, + `${url_Backend_dwinzo}/api/v2/Project/archive/${projectId}`, { method: "PATCH", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, body: JSON.stringify({ userId, organization }), } diff --git a/app/src/services/dashboard/getAllProjects.ts b/app/src/services/dashboard/getAllProjects.ts index 831f242..dc2e3b9 100644 --- a/app/src/services/dashboard/getAllProjects.ts +++ b/app/src/services/dashboard/getAllProjects.ts @@ -3,11 +3,14 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const getAllProjects = async (userId: string, organization: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/Projects/${userId}/${organization}`, + `${url_Backend_dwinzo}/api/v2/Projects`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); diff --git a/app/src/services/dashboard/getTrash.ts b/app/src/services/dashboard/getTrash.ts index b3487e5..f9db953 100644 --- a/app/src/services/dashboard/getTrash.ts +++ b/app/src/services/dashboard/getTrash.ts @@ -6,11 +6,14 @@ export const getTrash = async (organization: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/Trash/Lists?organization=${organization}`, + `${url_Backend_dwinzo}/api/v2/TrashItems`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); @@ -20,6 +23,7 @@ export const getTrash = async (organization: string) => { } const data = await response.json(); + console.log('TrashItems: ', data); return data; } catch (error: any) { console.error("Failed to fetch trash data:", error); diff --git a/app/src/services/dashboard/projectTutorial.ts b/app/src/services/dashboard/projectTutorial.ts index 4b9dc7c..bf7b121 100644 --- a/app/src/services/dashboard/projectTutorial.ts +++ b/app/src/services/dashboard/projectTutorial.ts @@ -9,7 +9,7 @@ export const projectTutorial = async () => { }, }); - console.log("response: ", response); + // console.log("response: ", response); if (!response.ok) { throw new Error("Failed to add project"); diff --git a/app/src/services/dashboard/recentlyViewed.ts b/app/src/services/dashboard/recentlyViewed.ts index 7a41169..c73998e 100644 --- a/app/src/services/dashboard/recentlyViewed.ts +++ b/app/src/services/dashboard/recentlyViewed.ts @@ -3,11 +3,14 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const recentlyViewed = async (organization: string, userId: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/RecentlyViewed/${userId}/${organization}`, + `${url_Backend_dwinzo}/api/v2/RecentlyViewed`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); @@ -15,6 +18,7 @@ export const recentlyViewed = async (organization: string, userId: string) => { if (!response.ok) { throw new Error("Failed to fetch project"); } + return await response.json(); } catch (error: any) { @@ -22,4 +26,3 @@ export const recentlyViewed = async (organization: string, userId: string) => { throw new Error(error.message); } }; - \ No newline at end of file diff --git a/app/src/services/dashboard/restoreTrash.ts b/app/src/services/dashboard/restoreTrash.ts index a157779..d1d6c90 100644 --- a/app/src/services/dashboard/restoreTrash.ts +++ b/app/src/services/dashboard/restoreTrash.ts @@ -4,11 +4,14 @@ const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_ export const restoreTrash = async (organization: string, projectId: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/restore?organization=${organization}&projectId=${projectId}`, + `${url_Backend_dwinzo}api/v2/Trash/restore?projectId=${projectId}`, { method: "PATCH", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); @@ -18,10 +21,10 @@ export const restoreTrash = async (organization: string, projectId: string) => { } const data = await response.json(); + console.log('restore: ', data); return data; } catch (error: any) { console.error("Failed to fetch trash data:", error); throw new Error(error.message || "Unknown error"); } }; - \ No newline at end of file diff --git a/app/src/services/dashboard/searchProjects.ts b/app/src/services/dashboard/searchProjects.ts index e7f858f..30a7062 100644 --- a/app/src/services/dashboard/searchProjects.ts +++ b/app/src/services/dashboard/searchProjects.ts @@ -7,11 +7,14 @@ export const searchProject = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/searchProjects?organization=${organization}&userId=${userId}&searchName=${searchName}`, + `${url_Backend_dwinzo}/api/v2/searchProjects?searchName=${searchName}`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); @@ -20,9 +23,9 @@ export const searchProject = async ( throw new Error("Failed to Search project"); } - console.log("response: ", response); + const result = await response.json(); - console.log("result: ", result); + console.log("searchProjects: ", result); return result; } catch (error) { diff --git a/app/src/services/dashboard/trashSearchProject.ts b/app/src/services/dashboard/trashSearchProject.ts index 06027e8..14c213f 100644 --- a/app/src/services/dashboard/trashSearchProject.ts +++ b/app/src/services/dashboard/trashSearchProject.ts @@ -7,11 +7,14 @@ export const trashSearchProject = async ( ) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/searchTrashProjects?organization=${organization}&userId=${userId}&searchName=${searchName}`, + `${url_Backend_dwinzo}/api/v2/searchTrashProjects?searchName=${searchName}`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); @@ -21,6 +24,7 @@ export const trashSearchProject = async ( } const result = await response.json(); + console.log('searchTrashProjects: ', result); return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/dashboard/updateProject.ts b/app/src/services/dashboard/updateProject.ts index 14c81fe..cf0d1a6 100644 --- a/app/src/services/dashboard/updateProject.ts +++ b/app/src/services/dashboard/updateProject.ts @@ -19,11 +19,14 @@ export const updateProject = async ( try { const response = await fetch( - `${url_Backend_dwinzo}/api/v1/Project/modify`, + `${url_Backend_dwinzo}/api/v2/Project/${projectId}`, { method: "PATCH", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, body: JSON.stringify(body), } diff --git a/app/src/services/dashboard/viewProject.ts b/app/src/services/dashboard/viewProject.ts index 408aadd..67a4316 100644 --- a/app/src/services/dashboard/viewProject.ts +++ b/app/src/services/dashboard/viewProject.ts @@ -1,17 +1,15 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const viewProject = async ( - organization: string, - projectId: string, - userId: string -) => { +export const viewProject = async (organization: string,projectId: string,userId: string) => { try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v1/Project/view?organization=${organization}&projectId=${projectId}&userId=${userId}`, + const response = await fetch(`${url_Backend_dwinzo}/api/v2/Project/${projectId}`, { method: "GET", headers: { + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", }, } ); diff --git a/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts b/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts index 2576769..22deb02 100644 --- a/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts +++ b/app/src/services/factoryBuilder/assest/assets/getAssetImages.ts @@ -3,9 +3,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL} export const getAssetImages = async (cursor?: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}/api/v3/AssetDatas?limit=10${ - cursor ? `&cursor=${cursor}` : "" - }`, + `${url_Backend_dwinzo}/api/v3/AssetDatas?limit=10${cursor ? `&cursor=${cursor}` : ""}`, { method: "GET", headers: { diff --git a/app/src/services/factoryBuilder/signInSignUp/signInApi.ts b/app/src/services/factoryBuilder/signInSignUp/signInApi.ts index d45eadb..9acd244 100644 --- a/app/src/services/factoryBuilder/signInSignUp/signInApi.ts +++ b/app/src/services/factoryBuilder/signInSignUp/signInApi.ts @@ -1,23 +1,18 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const signInApi = async ( - email: string, - password: Object, - organization: Object -) => { +export const signInApi = async (Email: string,Password: Object,organization: Object,fingerprint:any) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/login`, { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/Auth/login`, { method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ email, password, organization }), + headers: {"Content-Type": "application/json",}, + body: JSON.stringify({ Email, Password, organization,fingerprint}), }); const result = await response.json(); + return result; } catch (error) { - echo.error("Failed to sign-in"); + echo.error("Failed to sign-in"); if (error instanceof Error) { return { error: error.message }; } else { diff --git a/app/src/services/factoryBuilder/signInSignUp/signUpApi.ts b/app/src/services/factoryBuilder/signInSignUp/signUpApi.ts index 29939fb..859b8ec 100644 --- a/app/src/services/factoryBuilder/signInSignUp/signUpApi.ts +++ b/app/src/services/factoryBuilder/signInSignUp/signUpApi.ts @@ -2,17 +2,15 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const signUpApi = async ( userName: string, - email: string, - password: Object, + Email: string, + Password: Object, organization: Object ) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/signup`, { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/Auth/signup`, { method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ userName, email, password, organization }), + headers: { "Content-Type": "application/json", }, + body: JSON.stringify({ userName, Email, Password, organization }), }); if (!response.ok) { @@ -20,7 +18,6 @@ export const signUpApi = async ( } const result = await response.json(); - console.log("result: ", result); return result; } catch (error) { echo.error("Failed to sign-up"); -- 2.40.1 From 3d5159f1b6d0e737f8adc4d74ae2bfbd66aa3742 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 28 May 2025 12:07:31 +0530 Subject: [PATCH 05/21] Update Generated DXF Walls to backend --- .../components/temporary/SelectFloorPlan.tsx | 66 +++++--- app/src/modules/builder/builder.tsx | 8 +- app/src/modules/builder/dfx/LoadBlueprint.tsx | 147 +++++++++++++++--- .../functions/getWallPointsFromBlueprint.ts | 108 +++++++++---- app/src/store/builder/store.ts | 4 +- 5 files changed, 254 insertions(+), 79 deletions(-) diff --git a/app/src/components/temporary/SelectFloorPlan.tsx b/app/src/components/temporary/SelectFloorPlan.tsx index 8f16006..2035173 100644 --- a/app/src/components/temporary/SelectFloorPlan.tsx +++ b/app/src/components/temporary/SelectFloorPlan.tsx @@ -2,20 +2,25 @@ import React, { useEffect, useState } from "react"; import useLayoutStore from "../../store/builder/uselayoutStore"; import { useDfxUpload } from "../../store/builder/store"; import DxfParser from "dxf-parser"; -import { Box3, BufferGeometry, MathUtils, Vector3 } from "three"; import { getWallPointsFromBlueprint } from "../../modules/builder/dfx/functions/getWallPointsFromBlueprint"; import { convertDXFToThree } from "../../modules/builder/dfx/functions/convertDxfToThree"; -// Define types for DXF entities and geometries - const SelectFloorPlan: React.FC = () => { + // Access layout state and state setters const { currentLayout, setLayout } = useLayoutStore(); - const { setDfxUploaded, setDfxGenerate } = useDfxUpload(); + // Access DXF-related states and setters + const { setDfxUploaded, setDfxGenerate, setObjValue, objValue } = useDfxUpload(); - const [parsedFile, setParsedFile] = useState(); + // Local state to store the parsed DXF file + const [parsedFile, setParsedFile] = useState(undefined); + + // Flag to trigger generation after file upload const [generate, setGenerate] = useState(false); + // Handles file upload and DXF parsing const handleFileUpload = async (event: React.ChangeEvent) => { + setLayout(null); // Reset current layout + setParsedFile(undefined); // Clear any previously parsed file const file = event.target.files?.[0]; if (!file || !file.name.endsWith(".dxf")) { alert("Please upload a valid .dxf file."); @@ -23,47 +28,60 @@ const SelectFloorPlan: React.FC = () => { } const reader = new FileReader(); - reader.onload = async (e) => { const dxfContent = e.target?.result as string; try { const parser = new DxfParser(); - const parsedData = parser.parse(dxfContent) as DXFData; - const geometries = convertDXFToThree(parsedData); - - setParsedFile(parsedData); + const parsedDatas = parser.parse(dxfContent) as DXFData; + const geometries = convertDXFToThree(parsedDatas); + setParsedFile(parsedDatas); + setObjValue({ x: 0, y: 0, z: 0 }); setDfxUploaded(geometries); - } catch (error) { - echo.error("Failed to import your .dxf file") + console.error("Failed to import your .dxf file", error); + } finally { + // ✅ Reset input AFTER processing + event.target.value = ""; } }; - reader.readAsText(file); + reader.readAsText(file); // Read the uploaded file as text }; + // Trigger wall point generation when `generate` flag changes useEffect(() => { - if (parsedFile !== undefined) - getWallPointsFromBlueprint({ parsedData: parsedFile, setDfxGenerate }) - }, [generate]) + if (parsedFile !== undefined) { + getWallPointsFromBlueprint({ parsedData: parsedFile, setDfxGenerate, objValue }); + } + }, [generate]); + + useEffect(() => { + console.log("parsedFile: ", parsedFile); + }, [parsedFile]); return (
Preset Layouts +
+
-
+
); }; -export default SelectFloorPlan; - - - - - +export default SelectFloorPlan; \ No newline at end of file diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 82c93ba..d6df0d0 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -314,7 +314,13 @@ export default function Builder() { - + diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx index 9be72dc..66fc558 100644 --- a/app/src/modules/builder/dfx/LoadBlueprint.tsx +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -1,38 +1,145 @@ -import { useEffect } from 'react'; -import { useDfxUpload, useToggleView } from '../../../store/builder/store'; -import { LineBasicMaterial, Line } from "three"; +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'; -const DxfFile = ({ floorPlanGroupPoint, currentLayerPoint, dragPointControls, floorPlanGroupLine, lines, setUpdateScene }: any) => { - const { dfxuploaded, dfxWallGenerate } = useDfxUpload(); +// 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) => { + // State management hooks + const { dfxuploaded, dfxWallGenerate, setObjValue, objValue } = useDfxUpload(); + const { setUpdateScene } = useUpdateScene(); const { toggleView } = useToggleView(); + const { socket } = useSocketStore(); + // Refs for storing line objects + const lineRefs = useRef([]); + + /** + * Effect hook that runs when DXF wall generation is triggered. + * Loads initial points and lines from the DXF data and updates the scene. + */ useEffect(() => { - if (dfxWallGenerate && dragPointControls && floorPlanGroupPoint && currentLayerPoint && floorPlanGroupLine) { - lines.current = dfxWallGenerate; + if ( + dfxWallGenerate && + dragPointControls && + floorPlanGroupPoint && + currentLayerPoint && + floorPlanGroupLine + ) { + // Store generated lines in ref + lines.current.push(...dfxWallGenerate); + dfxWallGenerate.map((line: any) => { + const lineData = arrayLineToObject(line as Types.Line); + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + + //REST + + // setLine(organization, lineData.layer!, lineData.line!, lineData.type!); + + //SOCKET + + const input = { + organization: organization, + layer: lineData.layer, + line: lineData.line, + type: lineData.type, + socketId: socket.id + } + + 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]) + }, [ + lines, + floorPlanGroupLine, + floorPlanGroupPoint, + currentLayerPoint, + dragPointControls, + dfxWallGenerate, + ]); + + /** + * Handles transformation changes for individual lines. + * Updates the object value state with new position and recalculates wall points. + * @param index - Index of the line being transformed + */ + const handleTransformChange = (index: number) => { + const line = lineRefs.current[index]; + if (!line) return; + + // Get current position of the line + const position = line.position; + + // Update state with new position + setObjValue({ x: position.x, y: position.y, z: position.z }); + + // Recalculate wall points based on new position + getWallPointsFromBlueprint({ + objValue: { x: position.x, y: position.y, z: position.z }, + setDfxGenerate: () => { }, + }); + }; return ( <> - {dfxuploaded && dfxuploaded.length > 0 && toggleView && dfxuploaded?.map((geometry: any, index: any) => ( - - - 0 && + toggleView && + dfxuploaded?.map((geometry: any, index: number) => { + // Create a new line object for each geometry in the DXF data + const line = new Line(geometry, new LineBasicMaterial({ color: 'red' })); + line.rotation.set(-Math.PI / 2, 0, 0); + + // Store line reference + lineRefs.current[index] = line; + + return ( + - - - ))} + object={line} + onMouseUp={() => handleTransformChange(index)} + > + {/* Render the line with current position from state */} + + + ); + })} ); -} +}; -export default DxfFile; +export default DxfFile; \ No newline at end of file diff --git a/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts b/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts index 72057dd..13cae84 100644 --- a/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts +++ b/app/src/modules/builder/dfx/functions/getWallPointsFromBlueprint.ts @@ -1,41 +1,59 @@ import { MathUtils, Vector3, BufferGeometry } from "three"; interface Props { - parsedData: DXFData; - setDfxGenerate: (walls: WallLineVertex[][]) => void; + parsedData?: DXFData; // Parsed DXF file data + setDfxGenerate?: (walls: WallLineVertex[][]) => void; // Callback to set generated walls + objValue: any; // Object position values for offset calculation } +/** + * Processes DXF entities to generate wall points for a blueprint. + * Handles LINE, LWPOLYLINE, and ARC entity types, converting them to wall segments. + * Applies unit conversion and positional offsets to all points. + * + * @param {Props} params - Configuration parameters + * @param {DXFData} params.parsedData - Parsed DXF file data + * @param {Function} params.setDfxGenerate - Callback to store generated walls + * @param {Object} params.objValue - Contains x,y,z offsets for position adjustment + */ export function getWallPointsFromBlueprint({ parsedData, setDfxGenerate, + objValue, }: Props) { + // Early return if no data is provided + if (!parsedData) return; if (!parsedData.entities) return; - const unit = 1000; // Convert mm to meters - - const wallVertex: WallLineVertex[][] = []; + const unit = 1000; // Conversion factor from millimeters to meters + const wallVertex: WallLineVertex[][] = []; // Stores all generated wall segments + // Process each entity in the DXF file parsedData.entities.forEach((entity: DXFEntity) => { + // Handle LINE entities if (entity.type === "LINE" && entity.vertices) { + // Create start and end vectors with unit conversion and position offset const startVec = new Vector3( entity.vertices[0].x / unit, - 0.01, - -entity.vertices[0].y / unit - ); + 0.01, // Slightly above ground to avoid z-fighting + -entity.vertices[0].y / unit // Invert Y-axis to match Three.js coordinate system + ).add(new Vector3(objValue.x, 0, objValue.z)); + const endVec = new Vector3( entity.vertices[1].x / unit, 0.01, -entity.vertices[1].y / unit - ); + ).add(new Vector3(objValue.x, 0, objValue.z)); + // Check if points already exist to avoid duplicates const existingStart = wallVertex .flat() .find((v) => v[0].equals(startVec)); const startPoint: WallLineVertex = existingStart || [ startVec, - MathUtils.generateUUID(), - 1, - "WallLine", + MathUtils.generateUUID(), // Generate unique ID for new points + 1, // Default weight + "WallLine", // Type identifier ]; const existingEnd = wallVertex.flat().find((v) => v[0].equals(endVec)); @@ -46,22 +64,29 @@ export function getWallPointsFromBlueprint({ "WallLine", ]; + // Add the line segment to our collection wallVertex.push([startPoint, endPoint]); - } else if (entity.type === "LWPOLYLINE" && entity.vertices) { - let firstPoint: WallLineVertex | undefined; + } + // Handle LWPOLYLINE entities (connected line segments) + else if (entity.type === "LWPOLYLINE" && entity.vertices) { + let firstPoint: WallLineVertex | undefined; // Store first point for closing the polyline + // Process each vertex pair in the polyline for (let i = 0; i < entity.vertices.length - 1; i++) { + // Convert vertices to Three.js vectors with offset const startVec = new Vector3( entity.vertices[i].x / unit, 0.01, -entity.vertices[i].y / unit - ); + ).add(new Vector3(objValue.x, 0, objValue.z)); + const endVec = new Vector3( entity.vertices[i + 1].x / unit, 0.01, -entity.vertices[i + 1].y / unit - ); + ).add(new Vector3(objValue.x, 0, objValue.z)); + // Check for existing points const existingStart = wallVertex .flat() .find((v) => v[0].equals(startVec)); @@ -82,36 +107,52 @@ export function getWallPointsFromBlueprint({ wallVertex.push([startPoint, endPoint]); + // Store first point and create closing segment if this is the last vertex if (i === 0) firstPoint = startPoint; - if (i === entity.vertices.length - 2 && firstPoint) + if (i === entity.vertices.length - 2 && firstPoint) { wallVertex.push([endPoint, firstPoint]); + } } - } else if (entity.type === "ARC") { + } + // Handle ARC entities + else if (entity.type === "ARC") { const { center, radius, startAngle, endAngle } = entity; + // Validate required ARC properties if ( !center || radius === undefined || startAngle === undefined || endAngle === undefined - ) + ) { return; - - const numSegments = 16; - const angleStep = (endAngle - startAngle) / numSegments; - - const arcPoints: Vector3[] = []; - - for (let i = 0; i <= numSegments; i++) { - const angle = startAngle + i * angleStep; - const x = center.x + radius * Math.cos(angle); - const y = -center.y + radius * Math.sin(angle); - arcPoints.push(new Vector3(x / unit, 0.01, y / unit)); } + // Convert ARC to series of line segments + const numSegments = 16; // Number of segments to approximate the arc + const angleStep = (endAngle - startAngle) / numSegments; + const arcPoints: Vector3[] = []; // Stores points along the arc + + // Generate points along the arc + for (let i = 0; i <= numSegments; i++) { + const angle = startAngle + i * angleStep; + // Calculate arc point in DXF coordinate system + const x = center.x + radius * Math.cos(angle); + const y = -center.y + radius * Math.sin(angle); // Invert Y-axis + + // Convert to Three.js vector with offset + const vec = new Vector3(x / unit, 0.01, y / unit).add( + new Vector3(objValue.x, 0, objValue.z) + ); + + arcPoints.push(vec); + } + + // Create line segments between arc points for (let i = 0; i < arcPoints.length - 1; i++) { const startVec = arcPoints[i]; const endVec = arcPoints[i + 1]; + // Check for existing points const existingStart = wallVertex .flat() .find((v) => v[0].equals(startVec)); @@ -132,10 +173,13 @@ export function getWallPointsFromBlueprint({ wallVertex.push([startPoint, endPoint]); } - } else { + } + // Log unsupported entity types + else { console.error("Unsupported entity type:", entity.type); } }); - setDfxGenerate(wallVertex); + // Return the generated walls through callback if provided + setDfxGenerate && setDfxGenerate(wallVertex); } diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index c0af867..01dc754 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -494,8 +494,10 @@ export const useProcessBar = create((set: any) => ({ export const useDfxUpload = create((set: any) => ({ dfxuploaded: [], dfxWallGenerate: [], + objValue: { x: 0, y: 0, z: 0 }, setDfxUploaded: (x: any) => set({ dfxuploaded: x }), setDfxGenerate: (x: any) => set({ dfxWallGenerate: x }), + setObjValue: (x: any) => set({ objValue: x }), })); type InputValuesStore = { @@ -551,7 +553,7 @@ interface CompareStore { } export const useCompareStore = create((set) => ({ - comparePopUp: false, + comparePopUp: true, setComparePopUp: (value) => set({ comparePopUp: value }), toggleComparePopUp: () => set((state) => ({ comparePopUp: !state.comparePopUp })), -- 2.40.1 From c0fed911eba9e00a3716eef0acbba1c38f2de8e3 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 28 May 2025 12:40:40 +0530 Subject: [PATCH 06/21] Refactor SelectFloorPlan component by removing debug useEffect and cleaning up setGenerate calls; add showY prop to TransformControls in DxfFile component; initialize package-lock.json --- app/src/components/temporary/SelectFloorPlan.tsx | 7 ++----- app/src/modules/builder/dfx/LoadBlueprint.tsx | 1 + package-lock.json | 6 ++++++ 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 package-lock.json diff --git a/app/src/components/temporary/SelectFloorPlan.tsx b/app/src/components/temporary/SelectFloorPlan.tsx index 2035173..5056e4c 100644 --- a/app/src/components/temporary/SelectFloorPlan.tsx +++ b/app/src/components/temporary/SelectFloorPlan.tsx @@ -56,9 +56,6 @@ const SelectFloorPlan: React.FC = () => { } }, [generate]); - useEffect(() => { - console.log("parsedFile: ", parsedFile); - }, [parsedFile]); return (
@@ -70,7 +67,7 @@ const SelectFloorPlan: React.FC = () => { onClick={() => { setLayout("layout1"); setDfxUploaded([]); - setGenerate(false); + setGenerate(false); }} > Preset 1 @@ -112,7 +109,7 @@ const SelectFloorPlan: React.FC = () => { onClick={() => { setDfxUploaded([]); setLayout(null); - setGenerate(!generate); + setGenerate(!generate); }} > Generate diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx index 66fc558..8e0a1ab 100644 --- a/app/src/modules/builder/dfx/LoadBlueprint.tsx +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -131,6 +131,7 @@ const DxfFile = ({ handleTransformChange(index)} > {/* Render the line with current position from state */} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5ef6c4e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "Dwinzo_dev", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} -- 2.40.1 From c8627e0249e0a6e45f779709582ac0f998cb0eaf Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Thu, 29 May 2025 09:55:31 +0530 Subject: [PATCH 07/21] Refactor DashboardCard component: add active prop handling and improve option click logic --- .../components/Dashboard/DashboardCard.tsx | 35 ++++++++++++++++--- .../components/Dashboard/DashboardTrash.tsx | 1 + app/src/services/dashboard/recentlyViewed.ts | 6 ++-- app/src/services/dashboard/restoreTrash.ts | 2 +- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/app/src/components/Dashboard/DashboardCard.tsx b/app/src/components/Dashboard/DashboardCard.tsx index 75378b1..7ff0caf 100644 --- a/app/src/components/Dashboard/DashboardCard.tsx +++ b/app/src/components/Dashboard/DashboardCard.tsx @@ -13,6 +13,7 @@ interface DashBoardCardProps { projectId: string; handleDeleteProject?: (projectId: string) => Promise; handleRestoreProject?: (projectId: string) => Promise; + active?: string; } const DashboardCard: React.FC = ({ @@ -21,6 +22,7 @@ const DashboardCard: React.FC = ({ thumbnail, projectId, handleRestoreProject, + active }) => { const navigate = useNavigate(); const { setProjectName } = useProjectName(); @@ -42,7 +44,6 @@ const DashboardCard: React.FC = ({ }; const handleOptionClick = async (option: string) => { - console.log('option: ', option); switch (option) { case "delete": if (handleDeleteProject) { @@ -54,7 +55,13 @@ const DashboardCard: React.FC = ({ await handleRestoreProject(projectId); } break; - case "openInNewTab": + case "open in new tab": + try { + await viewProject(organization, projectId, userId); + setProjectName(projectName); // optional depending on scope + } catch (error) { + console.error("Error opening project in new tab:", error); + } window.open(`/${projectId}`, "_blank"); break; case "rename": @@ -111,9 +118,9 @@ const DashboardCard: React.FC = ({
- {isKebabOpen && ( + {isKebabOpen && active !== "trash" && (
- {["rename", "restore", "delete", "duplicate", "open in new tab"].map((option) => ( + {["rename", "delete", "duplicate", "open in new tab"].map((option) => (
)} - + {isKebabOpen && active && active == "trash" && ( + < div className="kebab-options-wrapper"> + {["restore", "delete"].map((option) => ( + + ))} + + ) + } + ); }; diff --git a/app/src/components/Dashboard/DashboardTrash.tsx b/app/src/components/Dashboard/DashboardTrash.tsx index 17de39b..06bf179 100644 --- a/app/src/components/Dashboard/DashboardTrash.tsx +++ b/app/src/components/Dashboard/DashboardTrash.tsx @@ -96,6 +96,7 @@ const DashboardTrash: React.FC = () => { thumbnail={project.thumbnail} projectId={project._id} handleRestoreProject={handleRestoreProject} + active={"trash"} /> )); }; diff --git a/app/src/services/dashboard/recentlyViewed.ts b/app/src/services/dashboard/recentlyViewed.ts index 0b42c08..78a0696 100644 --- a/app/src/services/dashboard/recentlyViewed.ts +++ b/app/src/services/dashboard/recentlyViewed.ts @@ -7,9 +7,9 @@ export const recentlyViewed = async (organization: string, userId: string) => { { method: "GET", headers: { - Authorization: "Bearer ", // Replace with actual token + Authorization: "Bearer ", // Replace with actual token "Content-Type": "application/json", - token: localStorage.getItem("token") || "", // Coerce null to empty string + token: localStorage.getItem("token") || "", // Coerce null to empty string refresh_token: localStorage.getItem("refreshToken") || "", }, } @@ -18,9 +18,7 @@ export const recentlyViewed = async (organization: string, userId: string) => { if (!response.ok) { throw new Error("Failed to fetch project"); } - - console.log('response: ', response); return await response.json(); } catch (error: any) { console.error("Failed to get project"); diff --git a/app/src/services/dashboard/restoreTrash.ts b/app/src/services/dashboard/restoreTrash.ts index 8e234b1..2af5d06 100644 --- a/app/src/services/dashboard/restoreTrash.ts +++ b/app/src/services/dashboard/restoreTrash.ts @@ -4,7 +4,7 @@ const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_ export const restoreTrash = async (organization: string, projectId: string) => { try { const response = await fetch( - `${url_Backend_dwinzo}api/v2/Trash/restore?projectId=${projectId}`, + `${url_Backend_dwinzo}/api/v2/Trash/restore?projectId=${projectId}`, { method: "PATCH", headers: { -- 2.40.1 From c77abff4248284183b33aea8b91a62df3137ecc2 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Thu, 29 May 2025 14:29:53 +0530 Subject: [PATCH 08/21] Implement rename mode functionality and integrate RenameTooltip component; update state management for renaming and mouse interactions in FloorGroup and Project components. --- .../components/ui/features/RenameTooltip.tsx | 7 ++- app/src/modules/builder/groups/floorGroup.tsx | 19 +++++++- .../modules/builder/groups/floorPlanGroup.tsx | 1 - app/src/pages/Project.tsx | 31 +++++++++++++ app/src/store/builder/store.ts | 5 ++ .../utils/shortcutkeys/handleShortcutKeys.ts | 46 ++++++++++++------- 6 files changed, 87 insertions(+), 22 deletions(-) diff --git a/app/src/components/ui/features/RenameTooltip.tsx b/app/src/components/ui/features/RenameTooltip.tsx index 180ba85..87de122 100644 --- a/app/src/components/ui/features/RenameTooltip.tsx +++ b/app/src/components/ui/features/RenameTooltip.tsx @@ -4,6 +4,7 @@ import { useLeftData, useTopData, } from "../../../store/visualization/useZone3DWidgetStore"; +import { useRenameModeStore } from "../../../store/builder/store"; type RenameTooltipProps = { name: string; @@ -13,12 +14,14 @@ type RenameTooltipProps = { const RenameTooltip: React.FC = ({ name, onSubmit }) => { const [value, setValue] = useState(name); - const { top } = useTopData(); - const { left } = useLeftData(); + const { top, setTop } = useTopData(); + const { left, setLeft } = useLeftData(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); onSubmit(value.trim()); + setTop(0); + setLeft(0); }; return ( diff --git a/app/src/modules/builder/groups/floorGroup.tsx b/app/src/modules/builder/groups/floorGroup.tsx index 2c2a8df..2cf5586 100644 --- a/app/src/modules/builder/groups/floorGroup.tsx +++ b/app/src/modules/builder/groups/floorGroup.tsx @@ -6,6 +6,7 @@ import { useToggleView, useWallVisibility, useUpdateScene, + useRenameModeStore, } from "../../../store/builder/store"; import hideRoof from "../geomentries/roofs/hideRoof"; import hideWalls from "../geomentries/walls/hideWalls"; @@ -15,6 +16,7 @@ import addPillar from "../geomentries/pillars/addPillar"; import DeletePillar from "../geomentries/pillars/deletePillar"; import DeletableHoveredPillar from "../geomentries/pillars/deletableHoveredPillar"; import loadFloor from "../geomentries/floors/loadFloor"; +import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore"; const FloorGroup = ({ floorGroup, @@ -30,6 +32,9 @@ const FloorGroup = ({ const { addAction } = useAddAction(); const { deleteTool } = useDeleteTool(); const { updateScene, setUpdateScene } = useUpdateScene(); + const { setTop } = useTopData(); + const { setLeft } = useLeftData(); + const { isRenameMode, setIsRenameMode } = useRenameModeStore(); useEffect(() => { if (updateScene) { @@ -55,6 +60,7 @@ const FloorGroup = ({ let isLeftMouseDown = false; const onMouseDown = (evt: any) => { + if (evt.button === 0) { isLeftMouseDown = true; drag = false; @@ -62,6 +68,7 @@ const FloorGroup = ({ }; const onMouseUp = (evt: any) => { + setIsRenameMode(false); if (evt.button === 0) { isLeftMouseDown = false; if (!drag) { @@ -75,7 +82,15 @@ const FloorGroup = ({ } }; - const onMouseMove = () => { + const onMouseMove = (evt: any) => { + if (!canvasElement) return; + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = evt.clientX - canvasRect.left; + const relativeY = evt.clientY - canvasRect.top; + if (!isRenameMode) { + setTop(relativeY); + setLeft(relativeX); + } if (isLeftMouseDown) { drag = true; } @@ -90,7 +105,7 @@ const FloorGroup = ({ canvasElement.removeEventListener("mouseup", onMouseUp); canvasElement.removeEventListener("mousemove", onMouseMove); }; - }, [deleteTool, addAction]); + }, [deleteTool, addAction, isRenameMode]); useFrame(() => { hideRoof(roofVisibility, floorGroup, camera); diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index dfb52c3..74f0783 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -50,7 +50,6 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin getLines(organization).then((data) => { const Lines: Types.Lines = objectLinesToArray(data); - console.log('Lines: ', Lines); // const data = localStorage.getItem("Lines"); diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 3b75365..3fa0d0f 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -15,6 +15,8 @@ import { useLoadingProgress, useWidgetSubOption, useSaveVersion, + useRenameModeStore, + useSelectedFloorItem, } from "../store/builder/store"; import { useNavigate } from "react-router-dom"; import { usePlayButtonStore } from "../store/usePlayButtonStore"; @@ -39,6 +41,8 @@ import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useProductStore } from "../store/simulation/useProductStore"; +import RenameTooltip from "../components/ui/features/RenameTooltip"; +import { setFloorItemApi } from "../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -50,10 +54,13 @@ const Project: React.FC = () => { const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); const { setFloorItems } = useFloorItems(); + const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem(); const { setWallItems } = useWallItems(); const { setZones } = useZones(); const { isVersionSaved } = useSaveVersion(); const { products } = useProductStore(); + const { isRenameMode, setIsRenameMode } = useRenameModeStore(); + // console.log('isRenameMode: ', isRenameMode); useEffect(() => { if (!isVersionSaved) { @@ -112,6 +119,29 @@ const Project: React.FC = () => { setSelectedLayout(option); // Set selected layout console.log("Selected layout:", option); }; + + const handleObjectRename = async (newName: string) => { + const email = localStorage.getItem("email") ?? ""; + const organization = email?.split("@")[1]?.split(".")[0]; + let response = await setFloorItemApi( + organization, + selectedFloorItem.userData.modelUuid, + newName + ); + selectedFloorItem.userData.name = newName; + setSelectedFloorItem(selectedFloorItem); + setIsRenameMode(false); + setFloorItems((prevFloorItems: any[]) => + prevFloorItems.map((floorItems) => + floorItems.modelUuid === selectedFloorItem.userData.modelUuid + .id + ? { ...floorItems, modelName: response.modelName } + : floorItems + ) + ); + } + + return (
{!selectedUser && ( @@ -161,6 +191,7 @@ const Project: React.FC = () => { >
+ {isRenameMode && selectedFloorItem?.userData.name && } {selectedUser && } {isLogListVisible && ( diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 01dc754..e8440ce 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -297,6 +297,11 @@ export const useUserName = create((set: any) => ({ setUserName: (x: any) => set({ userName: x }), })); +export const useRenameModeStore = create((set: any) => ({ + isRenameMode: false, + setIsRenameMode: (state: boolean) => set({ isRenameMode: state }), +})); + export const useObjectPosition = create((set: any) => ({ objectPosition: { x: undefined, y: undefined, z: undefined }, setObjectPosition: (newObjectPosition: any) => diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index eb0e3c3..14403fd 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -6,7 +6,9 @@ import { useActiveTool, useAddAction, useDeleteTool, + useRenameModeStore, useSaveVersion, + useSelectedFloorItem, useSelectedWallItem, useShortcutStore, useToggleView, @@ -37,6 +39,8 @@ const KeyPressListener: React.FC = () => { const { setIsVersionSaved } = useSaveVersion(); const { isLogListVisible, setIsLogListVisible } = useLogger(); const { hidePlayer, setHidePlayer } = usePlayerStore(); + const { isRenameMode, setIsRenameMode } = useRenameModeStore(); + const { selectedFloorItem } = useSelectedFloorItem(); const isTextInput = (element: Element | null): boolean => element instanceof HTMLInputElement || @@ -152,9 +156,24 @@ const KeyPressListener: React.FC = () => { }; const handleKeyPress = (event: KeyboardEvent) => { - if (isTextInput(document.activeElement)) return; - const keyCombination = detectModifierKeys(event); + + if (isTextInput(document.activeElement) && keyCombination !== "ESCAPE") + return; + + if (keyCombination === "ESCAPE") { + console.log("esc"); + setWalkMode(false); + setActiveTool("cursor"); + setActiveSubTool("cursor"); + setIsPlaying(false); + clearSelectedZone(); + setShowShortcuts(false); + setIsVersionSaved(false); + setIsLogListVisible(false); + setIsRenameMode(false); + } + if ( !keyCombination || ["F5", "F11", "F12"].includes(event.key) || @@ -186,26 +205,17 @@ const KeyPressListener: React.FC = () => { setHidePlayer(!hidePlayer); } - if (keyCombination === "ESCAPE") { - setWalkMode(false); - setActiveTool("cursor"); - setActiveSubTool("cursor"); - setIsPlaying(false); - clearSelectedZone(); - setShowShortcuts(false); - setIsVersionSaved(false); - setIsLogListVisible(false); - } - if (keyCombination === "Ctrl+Shift+?") { setShowShortcuts(!showShortcuts); } + if (selectedFloorItem && keyCombination === "F2") { + setIsRenameMode(true); + } + // Placeholder for future implementation if ( - ["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+F"].includes( - keyCombination - ) + ["Ctrl+Z", "Ctrl+Y", "Ctrl+Shift+Z", "Ctrl+F"].includes(keyCombination) ) { // Implement undo/redo/help/find/shortcuts } @@ -223,7 +233,9 @@ const KeyPressListener: React.FC = () => { showShortcuts, isPlaying, isLogListVisible, - hidePlayer + hidePlayer, + selectedFloorItem, + isRenameMode, ]); return null; -- 2.40.1 From 44b6b4daabf3df14ccb77a74c4a0830c0db53296 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 2 Jun 2025 14:37:47 +0530 Subject: [PATCH 09/21] Uncomment socket connection and authentication in useSocketStore for Builder and Visualization --- app/src/store/builder/store.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 2b0f26d..fb5bf2f 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -12,18 +12,18 @@ export const useSocketStore = create((set: any, get: any) => ({ } const socket = io( - // `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { reconnection: true, - // auth: { email, organization }, + auth: { email, organization }, } ); const visualizationSocket = io( - // `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { reconnection: true, - // auth: { email, organization }, + auth: { email, organization }, } ); -- 2.40.1 From da741ed6dfbb0386c2303a3a479910a96f7591cd Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 3 Jun 2025 12:51:04 +0530 Subject: [PATCH 10/21] Refactor point and aisle handling to use pointUuid and aisleUuid consistently - Updated useAislePointSnapping and usePointSnapping to reference point.pointUuid instead of point.uuid. - Modified Point component to utilize point.pointUuid for snapping and position updates. - Changed useAisleStore methods to work with aisleUuid and point.pointUuid for better clarity and consistency. - Introduced new properties for junction aisles, including isFlipped, and updated related logic. - Added implementations for ArrowAisle, CircleAisle, and JunctionAisle components to handle rendering and interactions. --- .../properties/AisleProperties.tsx | 24 +- .../aisle/Instances/aisleInstances.tsx | 18 +- .../Instances/instance/aisleInstance.tsx | 15 + .../instance/aisleTypes/arrowAisle.tsx | 88 ++ .../instance/aisleTypes/circleAisle.tsx | 82 + .../instance/aisleTypes/junctionAisle.tsx | 125 ++ .../aisle/aisleCreator/aisleCreator.tsx | 104 +- .../aisle/aisleCreator/referenceAisle.tsx | 300 +++- app/src/modules/builder/builder.tsx | 21 - .../geomentries/aisles/addAilseToScene.ts | 56 - .../builder/geomentries/aisles/loadAisles.ts | 19 - .../builder/groups/floorGroupAisle.tsx | 242 --- app/src/modules/builder/groups/zoneGroup.tsx | 1353 +++++++++-------- .../point/helpers/useAisleDragSnap.tsx | 4 +- .../point/helpers/usePointSnapping.tsx | 2 +- app/src/modules/builder/point/point.tsx | 14 +- app/src/store/builder/useAisleStore.ts | 47 +- app/src/store/builder/useBuilderStore.ts | 12 + app/src/types/builderTypes.d.ts | 5 +- 19 files changed, 1424 insertions(+), 1107 deletions(-) create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx delete mode 100644 app/src/modules/builder/geomentries/aisles/addAilseToScene.ts delete mode 100644 app/src/modules/builder/geomentries/aisles/loadAisles.ts delete mode 100644 app/src/modules/builder/groups/floorGroupAisle.tsx diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx index 96ef288..a613699 100644 --- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -12,6 +12,7 @@ import Directional from "../../../../assets/image/aisleTypes/Directional.png"; import Dotted from "../../../../assets/image/aisleTypes/Dotted.png"; import Solid from "../../../../assets/image/aisleTypes/Solid.png"; import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; +import InputToggle from "../../../ui/inputs/InputToggle"; interface TextureItem { color: AisleColors; @@ -24,7 +25,7 @@ const AisleProperties: React.FC = () => { const [collapsePresets, setCollapsePresets] = useState(false); const [collapseTexture, setCollapseTexture] = useState(true); - const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength } = useBuilderStore(); + const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength, setIsFlipped } = useBuilderStore(); const aisleTextureList: TextureItem[] = [ { color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "" }, @@ -90,6 +91,10 @@ const AisleProperties: React.FC = () => { } }; + const handleIsFlippedChange = () => { + setIsFlipped(!aisleIsFlipped) + }; + const dashLengthValue = useMemo(() => { return dashLength.toString(); }, [aisleType, dashLength]); @@ -110,6 +115,10 @@ const AisleProperties: React.FC = () => { return aisleLength.toString(); }, [aisleType, aisleLength]); + const aisleIsFlipped = useMemo(() => { + return isFlipped; + }, [aisleType, isFlipped]); + const renderAdvancedProperties = () => { switch (aisleType) { case 'dashed-aisle': @@ -185,6 +194,19 @@ const AisleProperties: React.FC = () => { } ); + case 'junction-aisle': + return ( + <> + {aisleType && + + } + + ) default: return null; } diff --git a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx index 8964434..227b2de 100644 --- a/app/src/modules/builder/aisle/Instances/aisleInstances.tsx +++ b/app/src/modules/builder/aisle/Instances/aisleInstances.tsx @@ -16,8 +16,8 @@ function AisleInstances() { aisles.forEach(aisle => { aisle.points.forEach(point => { - if (!seenUuids.has(point.uuid)) { - seenUuids.add(point.uuid); + if (!seenUuids.has(point.pointUuid)) { + seenUuids.add(point.pointUuid); points.push(point); } }); @@ -27,7 +27,7 @@ function AisleInstances() { }, [aisles]); useEffect(() => { - console.log('aisles: ', aisles); + // console.log('aisles: ', aisles); }, [aisles]); return ( @@ -35,7 +35,7 @@ function AisleInstances() { {toggleView && {allPoints.map((point) => ( - + ))} } @@ -46,13 +46,13 @@ function AisleInstances() { const distance = new Vector3(...aisle.points[0].position).distanceTo(new Vector3(...aisle.points[1].position)); return ( - < React.Fragment key={aisle.uuid}> - + < React.Fragment key={aisle.aisleUuid}> + {toggleView &&
{distance.toFixed(2)} m
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx index 9afd3d6..c8ecdd7 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx @@ -1,6 +1,9 @@ +import ArrowAisle from './aisleTypes/arrowAisle'; import ArrowsAisle from './aisleTypes/arrowsAisle'; +import CircleAisle from './aisleTypes/circleAisle'; import DashedAisle from './aisleTypes/dashedAisle'; import DottedAisle from './aisleTypes/dottedAisle'; +import JunctionAisle from './aisleTypes/junctionAisle'; import SolidAisle from './aisleTypes/solidAisle'; function AisleInstance({ aisle }: { readonly aisle: Aisle }) { @@ -22,6 +25,18 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) { {aisle.type.aisleType === 'arrows-aisle' && ( )} + + {aisle.type.aisleType === 'arrow-aisle' && ( + + )} + + {aisle.type.aisleType === 'circle-aisle' && ( + + )} + + {aisle.type.aisleType === 'junction-aisle' && ( + + )} ); } diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx new file mode 100644 index 0000000..7a4e270 --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arrowAisle.tsx @@ -0,0 +1,88 @@ +import * as THREE from 'three'; +import { useMemo, useRef } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; +import { useToolMode } from '../../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore'; + +function ArrowAisle({ aisle }: { readonly aisle: Aisle }) { + const aisleRef = useRef(null); + const { toolMode } = useToolMode(); + const { setSelectedAisle, hoveredPoint } = useBuilderStore(); + + const arrow = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const shape = new THREE.Shape(); + const arrowHeadLength = width * 2; + const shaftLength = length - arrowHeadLength; + + if (shaftLength > 0) { + shape.moveTo(0, 0); + shape.lineTo(width, -arrowHeadLength); + shape.lineTo(width / 2, -arrowHeadLength); + shape.lineTo(width / 2, -length); + shape.lineTo(-width / 2, -length); + shape.lineTo(-width / 2, -arrowHeadLength); + shape.lineTo(-width, -arrowHeadLength); + shape.lineTo(0, 0); + } else { + shape.moveTo(0, 0); + shape.lineTo(width, -length); + shape.lineTo(-width, -length); + shape.lineTo(0, 0); + } + + shape.closePath(); + + const position = end; + const angle = Math.atan2(direction.x, direction.z); + + return { shape, position, rotationY: angle }; + }, [aisle]); + + const handleClick = () => { + if (toolMode === 'move' && !hoveredPoint) { + setSelectedAisle(aisleRef.current); + } + } + + if (!arrow) return null; + + return ( + { + setSelectedAisle(null); + }} + > + + + + + + + ); +} + +export default ArrowAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx new file mode 100644 index 0000000..34caf99 --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/circleAisle.tsx @@ -0,0 +1,82 @@ +import * as THREE from 'three'; +import { useMemo, useRef } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; +import { useToolMode } from '../../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore'; + +function CircleAisle({ aisle }: { readonly aisle: Aisle }) { + const aisleRef = useRef(null); + const { toolMode } = useToolMode(); + const { setSelectedAisle, hoveredPoint } = useBuilderStore(); + + const circle = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null; + + const center = new THREE.Vector3(...aisle.points[0].position); + const widthCenter = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + + const middleRadius = center.distanceTo(widthCenter); + + const innerRadius = Math.max(0, middleRadius - width / 2); + const outerRadius = middleRadius + width / 2; + + const shape = new THREE.Shape(); + shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false); + + if (innerRadius > 0) { + const hole = new THREE.Path(); + hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true); + shape.holes.push(hole); + } + + return { + shape, + position: center, + rotationY: 0 + }; + }, [aisle]); + + const handleClick = () => { + if (toolMode === 'move' && !hoveredPoint) { + setSelectedAisle(aisleRef.current); + } + } + + if (!circle) return null; + + return ( + { + setSelectedAisle(null); + }} + > + + + + + + + ); +} + +export default CircleAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx new file mode 100644 index 0000000..52cab85 --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/junctionAisle.tsx @@ -0,0 +1,125 @@ +import * as THREE from 'three'; +import { useMemo, useRef } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; +import { useToolMode } from '../../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore'; + +function JunctionAisle({ aisle }: { readonly aisle: Aisle }) { + const aisleRef = useRef(null); + const { toolMode } = useToolMode(); + const { setSelectedAisle, hoveredPoint } = useBuilderStore(); + + const arrows = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + const isFlipped = aisle.type.isFlipped || false; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const mainShape = new THREE.Shape(); + const arrowHeadLength = width * 2; + const shaftLength = length - arrowHeadLength; + + if (shaftLength > 0) { + mainShape.moveTo(0, 0); + mainShape.lineTo(width, -arrowHeadLength); + mainShape.lineTo(width / 2, -arrowHeadLength); + mainShape.lineTo(width / 2, -length); + mainShape.lineTo(-width / 2, -length); + mainShape.lineTo(-width / 2, -arrowHeadLength); + mainShape.lineTo(-width, -arrowHeadLength); + mainShape.lineTo(0, 0); + } else { + mainShape.moveTo(0, 0); + mainShape.lineTo(width, -length); + mainShape.lineTo(-width, -length); + mainShape.lineTo(0, 0); + } + mainShape.closePath(); + + const secondaryLength = length / 4; + const secondaryShape = new THREE.Shape(); + const secondaryHeadLength = width * 2; + const secondaryShaftLength = secondaryLength - secondaryHeadLength; + + if (secondaryShaftLength > 0) { + secondaryShape.moveTo(0, 0); + secondaryShape.lineTo(width / 2, 0); + secondaryShape.lineTo(width / 2, secondaryShaftLength); + secondaryShape.lineTo(width, secondaryShaftLength); + secondaryShape.lineTo(0, secondaryLength); + secondaryShape.lineTo(-width, secondaryShaftLength); + secondaryShape.lineTo(-width / 2, secondaryShaftLength); + secondaryShape.lineTo(-width / 2, 0); + secondaryShape.lineTo(0, 0); + } else { + secondaryShape.moveTo(0, 0); + secondaryShape.lineTo(width, 0); + secondaryShape.lineTo(0, secondaryLength); + secondaryShape.lineTo(-width, 0); + secondaryShape.lineTo(0, 0); + } + secondaryShape.closePath(); + + const mainPosition = end; + const mainAngle = Math.atan2(direction.x, direction.z); + + const perpendicularDirection = isFlipped + ? new THREE.Vector3(direction.z, 0, -direction.x).normalize() + : new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const secondaryAngle = Math.atan2(perpendicularDirection.x, perpendicularDirection.z); + + const secondaryPosition = new THREE.Vector3().lerpVectors(start, end, 0.75); + + return [ + { shape: mainShape, position: mainPosition, rotationY: mainAngle }, + { shape: secondaryShape, position: secondaryPosition, rotationY: secondaryAngle + Math.PI } + ]; + }, [aisle]); + + const handleClick = () => { + if (toolMode === 'move' && !hoveredPoint) { + setSelectedAisle(aisleRef.current); + } + } + + if (!arrows) return null; + + return ( + { + setSelectedAisle(null); + }} + > + {arrows.map((arrow, index) => ( + + + + + + ))} + + ); +} + +export default JunctionAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx index 0b14967..dca5654 100644 --- a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx @@ -1,5 +1,5 @@ import * as THREE from 'three' -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import { useAisleStore } from '../../../../store/builder/useAisleStore'; @@ -15,45 +15,37 @@ function AisleCreator() { const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); const { addAisle, getAislePointById } = useAisleStore(); + const drag = useRef(false); + const isLeftMouseDown = useRef(false); const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); - const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, snappedPosition, snappedPoint } = useBuilderStore(); - - // useEffect(() => { - // if (tempPoints.length > 0) { - // setTempPoints([]); - // setIsCreating(false); - // } - // }, [aisleType]); + const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, snappedPosition, snappedPoint } = useBuilderStore(); useEffect(() => { const canvasElement = gl.domElement; - let drag = false; - let isLeftMouseDown = false; - const onMouseDown = (evt: any) => { if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; + isLeftMouseDown.current = true; + drag.current = false; } }; const onMouseUp = (evt: any) => { if (evt.button === 0) { - isLeftMouseDown = false; + isLeftMouseDown.current = false; } }; const onMouseMove = () => { if (isLeftMouseDown) { - drag = true; + drag.current = true; } }; const onMouseClick = () => { - if (drag || !toggleView) return; + if (drag.current || !toggleView) return; raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); @@ -63,14 +55,14 @@ function AisleCreator() { const intersects = raycaster.intersectObjects(scene.children).find((intersect) => intersect.object.name === 'Aisle-Point'); const newPoint: Point = { - uuid: THREE.MathUtils.generateUUID(), + pointUuid: THREE.MathUtils.generateUUID(), pointType: 'Aisle', position: [position.x, position.y, position.z], layer: activeLayer }; if (snappedPosition && snappedPoint) { - newPoint.uuid = snappedPoint.uuid; + newPoint.pointUuid = snappedPoint.pointUuid; newPoint.position = snappedPosition; newPoint.layer = snappedPoint.layer; } @@ -82,7 +74,7 @@ function AisleCreator() { if (intersects && !snappedPoint) { const point = getAislePointById(intersects.object.uuid); if (point) { - newPoint.uuid = point.uuid; + newPoint.pointUuid = point.pointUuid; newPoint.position = point.position; newPoint.layer = point.layer; } @@ -95,7 +87,7 @@ function AisleCreator() { setIsCreating(true); } else { const aisle: Aisle = { - uuid: THREE.MathUtils.generateUUID(), + aisleUuid: THREE.MathUtils.generateUUID(), points: [tempPoints[0], newPoint], type: { aisleType: 'solid-aisle', @@ -113,7 +105,7 @@ function AisleCreator() { setIsCreating(true); } else { const aisle: Aisle = { - uuid: THREE.MathUtils.generateUUID(), + aisleUuid: THREE.MathUtils.generateUUID(), points: [tempPoints[0], newPoint], type: { aisleType: 'dashed-aisle', @@ -133,7 +125,7 @@ function AisleCreator() { setIsCreating(true); } else { const aisle: Aisle = { - uuid: THREE.MathUtils.generateUUID(), + aisleUuid: THREE.MathUtils.generateUUID(), points: [tempPoints[0], newPoint], type: { aisleType: 'stripped-aisle', @@ -151,7 +143,7 @@ function AisleCreator() { setIsCreating(true); } else { const aisle: Aisle = { - uuid: THREE.MathUtils.generateUUID(), + aisleUuid: THREE.MathUtils.generateUUID(), points: [tempPoints[0], newPoint], type: { aisleType: 'dotted-aisle', @@ -164,7 +156,23 @@ function AisleCreator() { setTempPoints([newPoint]); } } else if (aisleType === 'arrow-aisle') { - console.log('Creating arrow-aisle'); + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + aisleUuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + aisleType: 'arrow-aisle', + aisleColor: aisleColor, + aisleWidth: aisleWidth + } + }; + addAisle(aisle); + setTempPoints([newPoint]); + } } else if (aisleType === 'arrows-aisle') { if (tempPoints.length === 0) { @@ -172,7 +180,7 @@ function AisleCreator() { setIsCreating(true); } else { const aisle: Aisle = { - uuid: THREE.MathUtils.generateUUID(), + aisleUuid: THREE.MathUtils.generateUUID(), points: [tempPoints[0], newPoint], type: { aisleType: 'arrows-aisle', @@ -188,9 +196,42 @@ function AisleCreator() { } else if (aisleType === 'arc-aisle') { console.log('Creating arc-aisle'); } else if (aisleType === 'circle-aisle') { - console.log('Creating circle-aisle'); + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + aisleUuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + aisleType: 'circle-aisle', + aisleColor: aisleColor, + aisleWidth: aisleWidth + } + }; + addAisle(aisle); + setTempPoints([newPoint]); + } } else if (aisleType === 'junction-aisle') { - console.log('Creating junction-aisle'); + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + aisleUuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + aisleType: 'junction-aisle', + aisleColor: aisleColor, + aisleWidth: aisleWidth, + isFlipped: isFlipped + } + }; + addAisle(aisle); + setTempPoints([newPoint]); + } } }; @@ -211,6 +252,11 @@ function AisleCreator() { } 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 () => { @@ -228,7 +274,7 @@ function AisleCreator() { <> {tempPoints.map((point) => ( - + ))} diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx index a4c331e..5bb18fd 100644 --- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -13,7 +13,7 @@ interface ReferenceAisleProps { } function ReferenceAisle({ tempPoints }: Readonly) { - const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, setSnappedPosition, setSnappedPoint } = useBuilderStore(); + const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setSnappedPosition, setSnappedPoint } = useBuilderStore(); const { pointer, raycaster, camera } = useThree(); const { toolMode } = useToolMode(); const { toggleView } = useToggleView(); @@ -24,7 +24,6 @@ function ReferenceAisle({ tempPoints }: Readonly) { const [tempAisle, setTempAisle] = useState(null); const [currentPosition, setCurrentPosition] = useState<[number, number, number]>(tempPoints[0]?.position); - // Calculate directional snap based on current and previous points const directionalSnap = useDirectionalSnapping( currentPosition, tempPoints[0]?.position || null @@ -61,11 +60,11 @@ function ReferenceAisle({ tempPoints }: Readonly) { if (aisleType === 'solid-aisle' || aisleType === 'stripped-aisle') { setTempAisle({ - uuid: 'temp-aisle', + aisleUuid: 'temp-aisle', points: [ tempPoints[0], { - uuid: 'temp-point', + pointUuid: 'temp-point', pointType: 'Aisle', position: finalPosition.current, layer: activeLayer @@ -79,11 +78,11 @@ function ReferenceAisle({ tempPoints }: Readonly) { }); } else if (aisleType === 'dashed-aisle') { setTempAisle({ - uuid: 'temp-aisle', + aisleUuid: 'temp-aisle', points: [ tempPoints[0], { - uuid: 'temp-point', + pointUuid: 'temp-point', pointType: 'Aisle', position: finalPosition.current, layer: activeLayer @@ -99,11 +98,11 @@ function ReferenceAisle({ tempPoints }: Readonly) { }); } else if (aisleType === 'dotted-aisle') { setTempAisle({ - uuid: 'temp-aisle', + aisleUuid: 'temp-aisle', points: [ tempPoints[0], { - uuid: 'temp-point', + pointUuid: 'temp-point', pointType: 'Aisle', position: finalPosition.current, layer: activeLayer @@ -116,15 +115,31 @@ function ReferenceAisle({ tempPoints }: Readonly) { gapLength: gapLength } }); - } else if (aisleType === 'arrow-aisle') { - console.log(); - } else if (aisleType === 'arrows-aisle') { + } else if (aisleType === 'arrow-aisle' || aisleType === 'circle-aisle') { setTempAisle({ - uuid: 'temp-aisle', + aisleUuid: 'temp-aisle', points: [ tempPoints[0], { - uuid: 'temp-point', + pointUuid: 'temp-point', + pointType: 'Aisle', + position: finalPosition.current, + layer: activeLayer + } + ], + type: { + aisleType: aisleType, + aisleColor: aisleColor, + aisleWidth: aisleWidth, + } + }); + } else if (aisleType === 'arrows-aisle') { + setTempAisle({ + aisleUuid: 'temp-aisle', + points: [ + tempPoints[0], + { + pointUuid: 'temp-point', pointType: 'Aisle', position: finalPosition.current, layer: activeLayer @@ -140,10 +155,25 @@ function ReferenceAisle({ tempPoints }: Readonly) { }); } else if (aisleType === 'arc-aisle') { console.log(); - } else if (aisleType === 'circle-aisle') { - console.log(); } else if (aisleType === 'junction-aisle') { - console.log(); + setTempAisle({ + aisleUuid: 'temp-aisle', + points: [ + tempPoints[0], + { + pointUuid: 'temp-point', + pointType: 'Aisle', + position: finalPosition.current, + layer: activeLayer + } + ], + type: { + aisleType: aisleType, + aisleColor: aisleColor, + aisleWidth: aisleWidth, + isFlipped: isFlipped, + } + }); } } } else if (tempAisle !== null) { @@ -165,8 +195,14 @@ function ReferenceAisle({ tempPoints }: Readonly) { return ; case 'dotted-aisle': return ; + case 'arrow-aisle': + return ; case 'arrows-aisle': - return + return ; + case 'circle-aisle': + return ; + case 'junction-aisle': + return ; default: return null; } @@ -182,7 +218,7 @@ function ReferenceAisle({ tempPoints }: Readonly) { {toggleView && ) { sprite >
{distance.toFixed(2)} m
@@ -446,3 +482,227 @@ function ArrowsAisle({ aisle }: { readonly aisle: Aisle }) { ); } + +function ArrowAisle({ aisle }: { readonly aisle: Aisle }) { + const arrow = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'arrow-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const shape = new THREE.Shape(); + const arrowHeadLength = width * 2; + const shaftLength = length - arrowHeadLength; + + if (shaftLength > 0) { + shape.moveTo(0, 0); + shape.lineTo(width, -arrowHeadLength); + shape.lineTo(width / 2, -arrowHeadLength); + shape.lineTo(width / 2, -length); + shape.lineTo(-width / 2, -length); + shape.lineTo(-width / 2, -arrowHeadLength); + shape.lineTo(-width, -arrowHeadLength); + shape.lineTo(0, 0); + } else { + shape.moveTo(0, 0); + shape.lineTo(width, -length); + shape.lineTo(-width, -length); + shape.lineTo(0, 0); + } + + shape.closePath(); + + const position = end; + const angle = Math.atan2(direction.x, direction.z); + + return { shape, position, rotationY: angle }; + }, [aisle]); + + if (!arrow) return null; + + return ( + + + + + + + + ); +} + +function CircleAisle({ aisle }: { readonly aisle: Aisle }) { + const circle = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'circle-aisle') return null; + + const center = new THREE.Vector3(...aisle.points[0].position); + const widthCenter = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + + const middleRadius = center.distanceTo(widthCenter); + + const innerRadius = Math.max(0, middleRadius - width / 2); + const outerRadius = middleRadius + width / 2; + + const shape = new THREE.Shape(); + shape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false); + + if (innerRadius > 0) { + const hole = new THREE.Path(); + hole.absarc(0, 0, innerRadius, 0, Math.PI * 2, true); + shape.holes.push(hole); + } + + return { + shape, + position: center, + rotationY: 0 + }; + }, [aisle]); + + if (!circle) return null; + + return ( + + + + + + + + ); +} + +function JunctionAisle({ aisle }: { readonly aisle: Aisle }) { + const arrows = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'junction-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.1; + const isFlipped = aisle.type.isFlipped || false; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const mainShape = new THREE.Shape(); + const arrowHeadLength = width * 2; + const shaftLength = length - arrowHeadLength; + + if (shaftLength > 0) { + mainShape.moveTo(0, 0); + mainShape.lineTo(width, -arrowHeadLength); + mainShape.lineTo(width / 2, -arrowHeadLength); + mainShape.lineTo(width / 2, -length); + mainShape.lineTo(-width / 2, -length); + mainShape.lineTo(-width / 2, -arrowHeadLength); + mainShape.lineTo(-width, -arrowHeadLength); + mainShape.lineTo(0, 0); + } else { + mainShape.moveTo(0, 0); + mainShape.lineTo(width, -length); + mainShape.lineTo(-width, -length); + mainShape.lineTo(0, 0); + } + mainShape.closePath(); + + const secondaryLength = length / 4; + const secondaryShape = new THREE.Shape(); + const secondaryHeadLength = width * 2; + const secondaryShaftLength = secondaryLength - secondaryHeadLength; + + if (secondaryShaftLength > 0) { + secondaryShape.moveTo(0, 0); + secondaryShape.lineTo(width / 2, 0); + secondaryShape.lineTo(width / 2, secondaryShaftLength); + secondaryShape.lineTo(width, secondaryShaftLength); + secondaryShape.lineTo(0, secondaryLength); + secondaryShape.lineTo(-width, secondaryShaftLength); + secondaryShape.lineTo(-width / 2, secondaryShaftLength); + secondaryShape.lineTo(-width / 2, 0); + secondaryShape.lineTo(0, 0); + } else { + secondaryShape.moveTo(0, 0); + secondaryShape.lineTo(width, 0); + secondaryShape.lineTo(0, secondaryLength); + secondaryShape.lineTo(-width, 0); + secondaryShape.lineTo(0, 0); + } + secondaryShape.closePath(); + + const mainPosition = end; + const mainAngle = Math.atan2(direction.x, direction.z); + + const perpendicularDirection = isFlipped + ? new THREE.Vector3(direction.z, 0, -direction.x).normalize() + : new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + + const secondaryAngle = Math.atan2(perpendicularDirection.x, perpendicularDirection.z); + + const secondaryPosition = new THREE.Vector3().lerpVectors(start, end, 0.75); + + return [ + { shape: mainShape, position: mainPosition, rotationY: mainAngle }, + { + shape: secondaryShape, + position: secondaryPosition, + rotationY: secondaryAngle + Math.PI + } + ]; + }, [aisle]); + + if (!arrows) return null; + + return ( + + {arrows.map((arrow, index) => ( + + + + + + ))} + + ); +} \ No newline at end of file diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index 3263b90..911d78c 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -35,7 +35,6 @@ 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 FloorGroupAilse from "./groups/floorGroupAisle"; import Draw from "./functions/draw"; import WallsAndWallItems from "./groups/wallsAndWallItems"; import Ground from "../scene/environment/ground"; @@ -275,26 +274,6 @@ export default function Builder() { - {/* */} - { - if (aisle.length >= 2 && aisle[0] && aisle[1]) { - const start: Types.Vector3 = aisle[0][0]; - const end: Types.Vector3 = aisle[1][0]; - - const direction = new THREE.Vector3( - end.x - start.x, - end.y - start.y, - end.z - start.z - ).normalize(); - - const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); - const offsetDistance = CONSTANTS.aisleConfig.width; - - const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance); - const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance); - const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance); - const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance); - - const stripShape = new THREE.Shape(); - stripShape.moveTo(leftStart.x, leftStart.z); - stripShape.lineTo(leftEnd.x, leftEnd.z); - stripShape.lineTo(rightEnd.x, rightEnd.z); - stripShape.lineTo(rightStart.x, rightStart.z); - stripShape.lineTo(leftStart.x, leftStart.z); - - const extrudeSettings = { - depth: CONSTANTS.aisleConfig.height, - bevelEnabled: false, - }; - - const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings); - const stripMaterial = new THREE.MeshStandardMaterial({ - color: CONSTANTS.aisleConfig.defaultColor, - polygonOffset: true, - polygonOffsetFactor: -1, - polygonOffsetUnits: -1, - }); - - const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial); - stripMesh.receiveShadow = true; - stripMesh.castShadow = true; - - stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01; - stripMesh.rotateX(Math.PI / 2); - - floorGroupAisle.current.add(stripMesh); - } -} diff --git a/app/src/modules/builder/geomentries/aisles/loadAisles.ts b/app/src/modules/builder/geomentries/aisles/loadAisles.ts deleted file mode 100644 index 437ae66..0000000 --- a/app/src/modules/builder/geomentries/aisles/loadAisles.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Types from '../../../../types/world/worldTypes'; -import addAisleToScene from './addAilseToScene'; -import * as CONSTANTS from '../../../../types/world/worldConstants'; - -export default async function loadAisles( - lines: Types.RefLines, - floorGroupAisle: Types.RefGroup -) { - // console.log('lines: ', lines.current[0][0][0]); - if (!floorGroupAisle.current) return - floorGroupAisle.current.children = []; - const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName); - - if (aisles.length > 0) { - aisles.forEach((aisle: Types.Line) => { - addAisleToScene(aisle, floorGroupAisle) - }) - } -} \ No newline at end of file diff --git a/app/src/modules/builder/groups/floorGroupAisle.tsx b/app/src/modules/builder/groups/floorGroupAisle.tsx deleted file mode 100644 index 2c65b64..0000000 --- a/app/src/modules/builder/groups/floorGroupAisle.tsx +++ /dev/null @@ -1,242 +0,0 @@ -import * as THREE from 'three'; -import * as Types from '../../../types/world/worldTypes'; -import * as CONSTANTS from '../../../types/world/worldConstants'; -import { useThree } from "@react-three/fiber"; -import { useToggleView, useActiveLayer, useSocketStore, useDeletePointOrLine, useUpdateScene, useNewLines, useToolMode } from "../../../store/builder/store"; -import { useEffect } from "react"; -import removeSoloPoint from "../geomentries/points/removeSoloPoint"; -import removeReferenceLine from "../geomentries/lines/removeReferenceLine"; -import getClosestIntersection from "../geomentries/lines/getClosestIntersection"; -import addPointToScene from "../geomentries/points/addPointToScene"; -import arrayLineToObject from '../geomentries/lines/lineConvertions/arrayLineToObject'; -import addLineToScene from "../geomentries/lines/addLineToScene"; -import loadAisles from '../geomentries/aisles/loadAisles'; - -const FloorGroupAilse = ({ floorGroupAisle, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => { - const { toggleView } = useToggleView(); - const { setDeletePointOrLine } = useDeletePointOrLine(); - const { toolMode } = useToolMode(); - const { socket } = useSocketStore(); - const { activeLayer } = useActiveLayer(); - const { gl, raycaster } = useThree(); - const { updateScene, setUpdateScene } = useUpdateScene(); - const { setNewLines } = useNewLines(); - - useEffect(() => { - if (updateScene) { - loadAisles(lines, floorGroupAisle); - setUpdateScene(false); - } - }, [updateScene]) - - useEffect(() => { - if (toolMode === "Aisle") { - setDeletePointOrLine(false); - } else { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }, [toolMode]); - - useEffect(() => { - - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = false; - } - } - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; - - const onContextMenu = (e: any) => { - e.preventDefault(); - if (toolMode === "Aisle") { - removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint); - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - }; - - const onMouseClick = (evt: any) => { - if (!plane.current || drag) return; - - const intersects = raycaster.intersectObject(plane.current, true); - let intersectionPoint = intersects[0].point; - const points = floorPlanGroupPoint.current?.children ?? []; - const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible); - let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); - - - if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) { - const lineType = intersectsLines[0].object.userData.linePoints[0][3]; - if (lineType === CONSTANTS.lineConfig.aisleName) { - // console.log("intersected a aisle line"); - const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); - let intersection = getClosestIntersection(ThroughPoint, intersectionPoint); - if (!intersection) return; - const point = addPointToScene(intersection, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName); - (line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - } - } else if (intersectsPoint && intersects && intersects.length > 0) { - if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.aisleName) { - // console.log("intersected a aisle point"); - intersectionPoint = intersectsPoint.object.position; - (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - ispreSnapped.current = false; - isSnapped.current = false; - } - } - } else if (intersects && intersects.length > 0) { - // console.log("intersected a empty area"); - let uuid: string = ""; - if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) { - intersectionPoint = anglesnappedPoint.current; - const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName); - uuid = point.uuid; - } else if (isSnapped.current && snappedPoint.current && line.current.length > 0) { - intersectionPoint = snappedPoint.current; - uuid = isSnappedUUID.current!; - } else if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - uuid = isSnappedUUID.current!; - } else { - const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.aisleOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.aisleName); - uuid = point.uuid; - } - (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.aisleName,]); - - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - lines.current.push(line.current as Types.Line); - - const data = arrayLineToObject(line.current as Types.Line); - - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - - //REST - - // setLine(organization, data.layer!, data.line!, data.type!); - - //SOCKET - - const input = { - organization: organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id - } - - socket.emit('v1:Line:create', input); - - setNewLines([line.current]); - - addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.pointConfig.aisleOuterColor, line.current, floorPlanGroupLine); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - ispreSnapped.current = false; - isSnapped.current = false; - } - } - } - - - if (toolMode === 'Aisle') { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("click", onMouseClick); - canvasElement.addEventListener("contextmenu", onContextMenu); - } - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("click", onMouseClick); - canvasElement.removeEventListener("contextmenu", onContextMenu); - }; - }, [toolMode]) - - - return ( - - - ) -} - -export default FloorGroupAilse; \ No newline at end of file diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index a18e265..349fe07 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -3,15 +3,15 @@ import { Html, Line, Sphere } from "@react-three/drei"; import { useThree, useFrame } from "@react-three/fiber"; import * as THREE from "three"; import { - useActiveLayer, - useDeleteTool, - useDeletePointOrLine, - useSocketStore, - useToggleView, - useToolMode, - useRemovedLayer, - useZones, - useZonePoints, + useActiveLayer, + useDeleteTool, + useDeletePointOrLine, + useSocketStore, + useToggleView, + useToolMode, + useRemovedLayer, + useZones, + useZonePoints, } from "../../../store/builder/store"; import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; @@ -21,42 +21,42 @@ import { computeArea } from "../functions/computeArea"; import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; const ZoneGroup: React.FC = () => { - const { camera, pointer, gl, raycaster, scene, controls } = useThree(); - const [startPoint, setStartPoint] = useState(null); - const [endPoint, setEndPoint] = useState(null); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - const [isDragging, setIsDragging] = useState(false); - const { selectedZone } = useSelectedZoneStore(); - const [draggedSphere, setDraggedSphere] = useState( - null - ); - const plane = useMemo( - () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), - [] - ); - const { toggleView } = useToggleView(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { removedLayer, setRemovedLayer } = useRemovedLayer(); - const { toolMode } = useToolMode(); - const { setDeleteTool } = useDeleteTool(); - const { activeLayer } = useActiveLayer(); - const { socket } = useSocketStore(); + const { camera, pointer, gl, raycaster, scene, controls } = useThree(); + const [startPoint, setStartPoint] = useState(null); + const [endPoint, setEndPoint] = useState(null); + const { zones, setZones } = useZones(); + const { zonePoints, setZonePoints } = useZonePoints(); + const [isDragging, setIsDragging] = useState(false); + const { selectedZone } = useSelectedZoneStore(); + const [draggedSphere, setDraggedSphere] = useState( + null + ); + const plane = useMemo( + () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), + [] + ); + const { toggleView } = useToggleView(); + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { removedLayer, setRemovedLayer } = useRemovedLayer(); + const { toolMode } = useToolMode(); + const { setDeleteTool } = useDeleteTool(); + const { activeLayer } = useActiveLayer(); + const { socket } = useSocketStore(); - const groupsRef = useRef(); + const groupsRef = useRef(); - const zoneMaterial = useMemo( - () => - new THREE.ShaderMaterial({ - side: THREE.DoubleSide, - vertexShader: ` + const zoneMaterial = useMemo( + () => + new THREE.ShaderMaterial({ + side: THREE.DoubleSide, + vertexShader: ` varying vec2 vUv; void main(){ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); vUv = uv; } `, - fragmentShader: ` + fragmentShader: ` varying vec2 vUv; uniform vec3 uOuterColor; void main(){ @@ -64,671 +64,674 @@ const ZoneGroup: React.FC = () => { gl_FragColor = vec4(uOuterColor, alpha); } `, - uniforms: { - uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, - }, - transparent: true, - depthWrite: false, - }), - [] - ); - - useEffect(() => { - const fetchZones = async () => { - const email = localStorage.getItem("email"); - if (!email) return; - - const organization = email.split("@")[1].split(".")[0]; - const data = await getZonesApi(organization); - - if (data.data && data.data.length > 0) { - const fetchedZones = data.data.map((zone: any) => ({ - zoneId: zone.zoneId, - zoneName: zone.zoneName, - points: zone.points, - viewPortCenter: zone.viewPortCenter, - viewPortposition: zone.viewPortposition, - layer: zone.layer, - })); - - setZones(fetchedZones); - - const fetchedPoints = data.data.flatMap((zone: any) => - zone.points - .slice(0, 4) - .map( - (point: [number, number, number]) => new THREE.Vector3(...point) - ) - ); - - setZonePoints(fetchedPoints); - } - }; - - fetchZones(); - }, []); - - useEffect(() => { - localStorage.setItem("zones", JSON.stringify(zones)); - }, [zones]); - - useEffect(() => { - if (removedLayer) { - const updatedZones = zones.filter( - (zone: any) => zone.layer !== removedLayer - ); - setZones(updatedZones); - - const updatedzonePoints = zonePoints.filter((_: any, index: any) => { - const zoneIndex = Math.floor(index / 4); - return zones[zoneIndex]?.layer !== removedLayer; - }); - setZonePoints(updatedzonePoints); - - zones - .filter((zone: any) => zone.layer === removedLayer) - .forEach((zone: any) => { - deleteZoneFromBackend(zone.zoneId); - }); - - setRemovedLayer(null); - } - }, [removedLayer]); - - useEffect(() => { - if (toolMode !== "Zone") { - setStartPoint(null); - setEndPoint(null); - } else { - setDeletePointOrLine(false); - setDeleteTool(false); - } - if (!toggleView) { - setStartPoint(null); - setEndPoint(null); - } - }, [toolMode, toggleView]); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const addZoneToBackend = async (zone: { - zoneId: string; - zoneName: string; - points: [number, number, number][]; - layer: string; - }) => { - const email = localStorage.getItem("email"); - const userId = localStorage.getItem("userId"); - const organization = email!.split("@")[1].split(".")[0]; - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, - sumY = 0, - sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ - number, - number, - number - ]; - }; - - const target: [number, number, number] | null = calculateCenter( - zone.points + uniforms: { + uOuterColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, + }, + transparent: true, + depthWrite: false, + }), + [] ); - if (!target || zone.points.length < 4) return; - const position = [target[0], 10, target[2]]; - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer, - }, - }; + useEffect(() => { + const fetchZones = async () => { + const email = localStorage.getItem("email"); + if (!email) return; - socket.emit("v2:zone:set", input); - }; + const organization = email.split("@")[1].split(".")[0]; + const data = await getZonesApi(organization); - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateZoneToBackend = async (zone: { - zoneId: string; - zoneName: string; - points: [number, number, number][]; - layer: string; - }) => { - const email = localStorage.getItem("email"); - const userId = localStorage.getItem("userId"); - const organization = email!.split("@")[1].split(".")[0]; + if (data.data && data.data.length > 0) { + const fetchedZones = data.data.map((zone: any) => ({ + zoneId: zone.zoneId, + zoneName: zone.zoneName, + points: zone.points, + viewPortCenter: zone.viewPortCenter, + viewPortposition: zone.viewPortposition, + layer: zone.layer, + })); - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; + console.log('fetchedZones: ', fetchedZones); + setZones(fetchedZones); - let sumX = 0, - sumY = 0, - sumZ = 0; - const numPoints = points.length; + const fetchedPoints = data.data.flatMap((zone: any) => + zone.points + .slice(0, 4) + .map( + (point: [number, number, number]) => new THREE.Vector3(...point) + ) + ); - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ - number, - number, - number - ]; - }; - - const target: [number, number, number] | null = calculateCenter( - zone.points - ); - if (!target || zone.points.length < 4) return; - const position = [target[0], 10, target[2]]; - - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer, - }, - }; - - socket.emit("v2:zone:set", input); - }; - - const deleteZoneFromBackend = async (zoneId: string) => { - const email = localStorage.getItem("email"); - const userId = localStorage.getItem("userId"); - const organization = email!.split("@")[1].split(".")[0]; - - const input = { - userId: userId, - organization: organization, - zoneId: zoneId, - }; - - socket.emit("v2:zone:delete", input); - }; - - // eslint-disable-next-line react-hooks/exhaustive-deps - const handleDeleteZone = (zoneId: string) => { - const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); - setZones(updatedZones); - - const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); - if (zoneIndex !== -1) { - const zonePointsToRemove = zonePoints.slice( - zoneIndex * 4, - zoneIndex * 4 + 4 - ); - zonePointsToRemove.forEach((point: any) => - groupsRef.current.remove(point) - ); - const updatedzonePoints = zonePoints.filter( - (_: any, index: any) => - index < zoneIndex * 4 || index >= zoneIndex * 4 + 4 - ); - setZonePoints(updatedzonePoints); - } - deleteZoneFromBackend(zoneId); - }; - - useEffect(() => { - if (!camera || !toggleView) return; - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects( - groupsRef.current.children, - true - ); - - if (intersects.length > 0 && toolMode === "move") { - const clickedObject = intersects[0].object; - const sphereIndex = zonePoints.findIndex((point: any) => - point.equals(clickedObject.position) - ); - if (sphereIndex !== -1) { - (controls as any).enabled = false; - setDraggedSphere(zonePoints[sphereIndex]); - setIsDragging(true); - } - } - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { - isLeftMouseDown = false; - - if (!startPoint && toolMode !== "move") { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setStartPoint(point); - setEndPoint(null); - } - } else if (startPoint && toolMode !== "move") { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (!point) return; - - const points = [ - [startPoint.x, 0.15, startPoint.z], - [point.x, 0.15, startPoint.z], - [point.x, 0.15, point.z], - [startPoint.x, 0.15, point.z], - [startPoint.x, 0.15, startPoint.z], - ] as [number, number, number][]; - - const zoneName = `Zone ${zones.length + 1}`; - const zoneId = THREE.MathUtils.generateUUID(); - const newZone = { - zoneId, - zoneName, - points: points, - layer: activeLayer, - }; - - const newZones = [...zones, newZone]; - - setZones(newZones); - - const newzonePoints = [ - new THREE.Vector3(startPoint.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, point.z), - new THREE.Vector3(startPoint.x, 0.15, point.z), - ]; - - const updatedZonePoints = [...zonePoints, ...newzonePoints]; - setZonePoints(updatedZonePoints); - - addZoneToBackend(newZone); - setStartPoint(null); - setEndPoint(null); - } - } else if ( - evt.button === 0 && - !drag && - !isDragging && - deletePointOrLine - ) { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects( - groupsRef.current.children, - true - ); - - if (intersects.length > 0) { - const clickedObject = intersects[0].object; - - const sphereIndex = zonePoints.findIndex((point: any) => - point.equals(clickedObject.position) - ); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const zoneId = zones[zoneIndex].zoneId; - handleDeleteZone(zoneId); - return; - } - } - } - - if (evt.button === 0) { - if (isDragging && draggedSphere) { - setIsDragging(false); - setDraggedSphere(null); - - const sphereIndex = zonePoints.findIndex( - (point: any) => point === draggedSphere - ); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - - if (zoneIndex !== -1 && zones[zoneIndex]) { - updateZoneToBackend(zones[zoneIndex]); + setZonePoints(fetchedPoints); } - } + }; + + fetchZones(); + }, []); + + useEffect(() => { + console.log('zones: ', zones); + localStorage.setItem("zones", JSON.stringify(zones)); + }, [zones]); + + useEffect(() => { + if (removedLayer) { + const updatedZones = zones.filter( + (zone: any) => zone.layer !== removedLayer + ); + setZones(updatedZones); + + const updatedzonePoints = zonePoints.filter((_: any, index: any) => { + const zoneIndex = Math.floor(index / 4); + return zones[zoneIndex]?.layer !== removedLayer; + }); + setZonePoints(updatedzonePoints); + + zones + .filter((zone: any) => zone.layer === removedLayer) + .forEach((zone: any) => { + deleteZoneFromBackend(zone.zoneId); + }); + + setRemovedLayer(null); } - } + }, [removedLayer]); + + useEffect(() => { + if (toolMode !== "Zone") { + setStartPoint(null); + setEndPoint(null); + } else { + setDeletePointOrLine(false); + setDeleteTool(false); + } + if (!toggleView) { + setStartPoint(null); + setEndPoint(null); + } + }, [toolMode, toggleView]); + + // eslint-disable-next-line react-hooks/exhaustive-deps + const addZoneToBackend = async (zone: { + zoneId: string; + zoneName: string; + points: [number, number, number][]; + layer: string; + }) => { + console.log('zoneId: ', zone); + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; + + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, + sumY = 0, + sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ + number, + number, + number + ]; + }; + + const target: [number, number, number] | null = calculateCenter( + zone.points + ); + if (!target || zone.points.length < 4) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer, + }, + }; + + socket.emit("v2:zone:set", input); }; - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects( - groupsRef.current.children, - true - ); + // eslint-disable-next-line react-hooks/exhaustive-deps + const updateZoneToBackend = async (zone: { + zoneId: string; + zoneName: string; + points: [number, number, number][]; + layer: string; + }) => { + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; - if ( - intersects.length > 0 && - intersects[0].object.name.includes("point") - ) { - gl.domElement.style.cursor = - toolMode === "move" ? "pointer" : "default"; - } else { - gl.domElement.style.cursor = "default"; - } - if (isDragging && draggedSphere) { + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, + sumY = 0, + sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ + number, + number, + number + ]; + }; + + const target: [number, number, number] | null = calculateCenter( + zone.points + ); + if (!target || zone.points.length < 4) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer, + }, + }; + + socket.emit("v2:zone:set", input); + }; + + const deleteZoneFromBackend = async (zoneId: string) => { + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; + + const input = { + userId: userId, + organization: organization, + zoneId: zoneId, + }; + + socket.emit("v2:zone:delete", input); + }; + + // eslint-disable-next-line react-hooks/exhaustive-deps + const handleDeleteZone = (zoneId: string) => { + const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); + setZones(updatedZones); + + const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); + if (zoneIndex !== -1) { + const zonePointsToRemove = zonePoints.slice( + zoneIndex * 4, + zoneIndex * 4 + 4 + ); + zonePointsToRemove.forEach((point: any) => + groupsRef.current.remove(point) + ); + const updatedzonePoints = zonePoints.filter( + (_: any, index: any) => + index < zoneIndex * 4 || index >= zoneIndex * 4 + 4 + ); + setZonePoints(updatedzonePoints); + } + deleteZoneFromBackend(zoneId); + }; + + useEffect(() => { + if (!camera || !toggleView) return; + const canvasElement = gl.domElement; + + let drag = false; + let isLeftMouseDown = false; + + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = true; + drag = false; + + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); + + if (intersects.length > 0 && toolMode === "move") { + const clickedObject = intersects[0].object; + const sphereIndex = zonePoints.findIndex((point: any) => + point.equals(clickedObject.position) + ); + if (sphereIndex !== -1) { + (controls as any).enabled = false; + setDraggedSphere(zonePoints[sphereIndex]); + setIsDragging(true); + } + } + } + }; + + const onMouseUp = (evt: any) => { + if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { + isLeftMouseDown = false; + + if (!startPoint && toolMode !== "move") { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + setStartPoint(point); + setEndPoint(null); + } + } else if (startPoint && toolMode !== "move") { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (!point) return; + + const points = [ + [startPoint.x, 0.15, startPoint.z], + [point.x, 0.15, startPoint.z], + [point.x, 0.15, point.z], + [startPoint.x, 0.15, point.z], + [startPoint.x, 0.15, startPoint.z], + ] as [number, number, number][]; + + const zoneName = `Zone ${zones.length + 1}`; + const zoneId = THREE.MathUtils.generateUUID(); + const newZone = { + zoneId, + zoneName, + points: points, + layer: activeLayer, + }; + + const newZones = [...zones, newZone]; + + setZones(newZones); + + const newzonePoints = [ + new THREE.Vector3(startPoint.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, point.z), + new THREE.Vector3(startPoint.x, 0.15, point.z), + ]; + + const updatedZonePoints = [...zonePoints, ...newzonePoints]; + setZonePoints(updatedZonePoints); + + addZoneToBackend(newZone); + setStartPoint(null); + setEndPoint(null); + } + } else if ( + evt.button === 0 && + !drag && + !isDragging && + deletePointOrLine + ) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); + + if (intersects.length > 0) { + const clickedObject = intersects[0].object; + + const sphereIndex = zonePoints.findIndex((point: any) => + point.equals(clickedObject.position) + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const zoneId = zones[zoneIndex].zoneId; + handleDeleteZone(zoneId); + return; + } + } + } + + if (evt.button === 0) { + if (isDragging && draggedSphere) { + setIsDragging(false); + setDraggedSphere(null); + + const sphereIndex = zonePoints.findIndex( + (point: any) => point === draggedSphere + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + + if (zoneIndex !== -1 && zones[zoneIndex]) { + updateZoneToBackend(zones[zoneIndex]); + } + } + } + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) { + drag = true; + } + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); + + if ( + intersects.length > 0 && + intersects[0].object.name.includes("point") + ) { + gl.domElement.style.cursor = + toolMode === "move" ? "pointer" : "default"; + } else { + gl.domElement.style.cursor = "default"; + } + if (isDragging && draggedSphere) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + draggedSphere.set(point.x, 0.15, point.z); + + const sphereIndex = zonePoints.findIndex( + (point: any) => point === draggedSphere + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const cornerIndex = sphereIndex % 4; + + const updatedZones = zones.map((zone: any, index: number) => { + if (index === zoneIndex) { + const updatedPoints = [...zone.points]; + updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; + updatedPoints[4] = updatedPoints[0]; + return { ...zone, points: updatedPoints }; + } + return zone; + }); + + setZones(updatedZones); + } + } + } + }; + + const onContext = (event: any) => { + event.preventDefault(); + setStartPoint(null); + setEndPoint(null); + }; + + if (toolMode === "Zone" || deletePointOrLine || toolMode === "move") { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("contextmenu", onContext); + } + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [ + gl, + camera, + startPoint, + toggleView, + scene, + toolMode, + zones, + isDragging, + deletePointOrLine, + zonePoints, + draggedSphere, + activeLayer, + raycaster, + pointer, + controls, + plane, + setZones, + setZonePoints, + addZoneToBackend, + handleDeleteZone, + updateZoneToBackend, + ]); + + useFrame(() => { + if (!startPoint) return; raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); const point = raycaster.ray.intersectPlane(plane, intersectionPoint); if (point) { - draggedSphere.set(point.x, 0.15, point.z); - - const sphereIndex = zonePoints.findIndex( - (point: any) => point === draggedSphere - ); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const cornerIndex = sphereIndex % 4; - - const updatedZones = zones.map((zone: any, index: number) => { - if (index === zoneIndex) { - const updatedPoints = [...zone.points]; - updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; - updatedPoints[4] = updatedPoints[0]; - return { ...zone, points: updatedPoints }; - } - return zone; - }); - - setZones(updatedZones); - } + setEndPoint(point); } - } - }; + }); - const onContext = (event: any) => { - event.preventDefault(); - setStartPoint(null); - setEndPoint(null); - }; + return ( + + + {zones.map((zone: any) => ( + + {zone.points + .slice(0, -1) + .map((point: [number, number, number], index: number) => { + const nextPoint = zone.points[index + 1]; - if (toolMode === "Zone" || deletePointOrLine || toolMode === "move") { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("contextmenu", onContext); - } - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("contextmenu", onContext); - }; - }, [ - gl, - camera, - startPoint, - toggleView, - scene, - toolMode, - zones, - isDragging, - deletePointOrLine, - zonePoints, - draggedSphere, - activeLayer, - raycaster, - pointer, - controls, - plane, - setZones, - setZonePoints, - addZoneToBackend, - handleDeleteZone, - updateZoneToBackend, - ]); + const point1 = new THREE.Vector3(point[0], point[1], point[2]); + const point2 = new THREE.Vector3( + nextPoint[0], + nextPoint[1], + nextPoint[2] + ); - useFrame(() => { - if (!startPoint) return; - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setEndPoint(point); - } - }); + const planeWidth = point1.distanceTo(point2); + const planeHeight = CONSTANTS.zoneConfig.height; - return ( - - - {zones.map((zone: any) => ( - - {zone.points - .slice(0, -1) - .map((point: [number, number, number], index: number) => { - const nextPoint = zone.points[index + 1]; + const midpoint = new THREE.Vector3( + (point1.x + point2.x) / 2, + CONSTANTS.zoneConfig.height / 2 + + (zone.layer - 1) * CONSTANTS.zoneConfig.height, + (point1.z + point2.z) / 2 + ); - const point1 = new THREE.Vector3(point[0], point[1], point[2]); - const point2 = new THREE.Vector3( - nextPoint[0], - nextPoint[1], - nextPoint[2] - ); + const angle = Math.atan2( + point2.z - point1.z, + point2.x - point1.x + ); - const planeWidth = point1.distanceTo(point2); - const planeHeight = CONSTANTS.zoneConfig.height; + return ( + + + + + ); + })} + {!toggleView && + (() => { + const points3D = zone.points || []; + const coords2D = points3D.map((p: any) => [p[0], p[2]]); - const midpoint = new THREE.Vector3( - (point1.x + point2.x) / 2, - CONSTANTS.zoneConfig.height / 2 + - (zone.layer - 1) * CONSTANTS.zoneConfig.height, - (point1.z + point2.z) / 2 - ); + // Ensure the polygon is closed + if ( + coords2D.length >= 4 && + (coords2D[0][0] !== coords2D[coords2D.length - 1][0] || + coords2D[0][1] !== coords2D[coords2D.length - 1][1]) + ) { + coords2D.push(coords2D[0]); + } + if (coords2D.length < 4) return null; - const angle = Math.atan2( - point2.z - point1.z, - point2.x - point1.x - ); + const polygon = turf.polygon([coords2D]); + const center2D = turf.center(polygon).geometry.coordinates; - return ( - - - sum + p[1], + 0 + ); + const avgY = points3D.length > 0 ? sumY / points3D.length : 0; + + const htmlPosition: [number, number, number] = [ + center2D[0], + avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5, + center2D[1], + ]; + + return ( + +
{zone.zoneName}
+ + ); + })()} +
+ ))} +
+ + {zones + .filter((zone: any) => zone.layer === activeLayer) + .map((zone: any) => ( + { + e.stopPropagation(); + if (deletePointOrLine) { + handleDeleteZone(zone.zoneId); + } + }} + /> + ))} + + + {zones.map((zone: any, index: any) => { + if (!toggleView) return null; + const points3D = zone.points; + const coords2D = points3D.map((p: any) => [p[0], p[2]]); + + if ( + coords2D.length < 4 || + coords2D[0][0] !== coords2D[coords2D.length - 1][0] || + coords2D[0][1] !== coords2D[coords2D.length - 1][1] + ) { + coords2D.push(coords2D[0]); + } + if (coords2D.length < 4) return null; + + const polygon = turf.polygon([coords2D]); + const center2D = turf.center(polygon).geometry.coordinates; + + const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0); + const avgY = sumY / points3D.length; + + const area = computeArea(points3D, "zone"); + const formattedArea = `${area.toFixed(2)} m²`; + + const htmlPosition: [number, number, number] = [ + center2D[0], + avgY + CONSTANTS.zoneConfig.height, + center2D[1], + ]; + return ( + +
+ {zone.zoneName} ({formattedArea}) +
+ + ); + })} +
+ + + {zones + .filter((zone: any) => zone.layer === activeLayer) + .flatMap((zone: any) => + zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( + + + + )) + )} + + + {startPoint && endPoint && ( + - - ); - })} - {!toggleView && - (() => { - const points3D = zone.points || []; - const coords2D = points3D.map((p: any) => [p[0], p[2]]); - - // Ensure the polygon is closed - if ( - coords2D.length >= 4 && - (coords2D[0][0] !== coords2D[coords2D.length - 1][0] || - coords2D[0][1] !== coords2D[coords2D.length - 1][1]) - ) { - coords2D.push(coords2D[0]); - } - if (coords2D.length < 4) return null; - - const polygon = turf.polygon([coords2D]); - const center2D = turf.center(polygon).geometry.coordinates; - - // Calculate the average Y value - const sumY = points3D.reduce( - (sum: number, p: any) => sum + p[1], - 0 - ); - const avgY = points3D.length > 0 ? sumY / points3D.length : 0; - - const htmlPosition: [number, number, number] = [ - center2D[0], - avgY + (CONSTANTS.zoneConfig.height || 0) + 1.5, - center2D[1], - ]; - - return ( - -
{zone.zoneName}
- - ); - })()} -
- ))} -
- - {zones - .filter((zone: any) => zone.layer === activeLayer) - .map((zone: any) => ( - { - e.stopPropagation(); - if (deletePointOrLine) { - handleDeleteZone(zone.zoneId); - } - }} - /> - ))} - - - {zones.map((zone: any, index: any) => { - if (!toggleView) return null; - const points3D = zone.points; - const coords2D = points3D.map((p: any) => [p[0], p[2]]); - - if ( - coords2D.length < 4 || - coords2D[0][0] !== coords2D[coords2D.length - 1][0] || - coords2D[0][1] !== coords2D[coords2D.length - 1][1] - ) { - coords2D.push(coords2D[0]); - } - if (coords2D.length < 4) return null; - - const polygon = turf.polygon([coords2D]); - const center2D = turf.center(polygon).geometry.coordinates; - - const sumY = points3D.reduce((sum: number, p: any) => sum + p[1], 0); - const avgY = sumY / points3D.length; - - const area = computeArea(points3D, "zone"); - const formattedArea = `${area.toFixed(2)} m²`; - - const htmlPosition: [number, number, number] = [ - center2D[0], - avgY + CONSTANTS.zoneConfig.height, - center2D[1], - ]; - return ( - -
- {zone.zoneName} ({formattedArea}) -
- - ); - })} -
- - - {zones - .filter((zone: any) => zone.layer === activeLayer) - .flatMap((zone: any) => - zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( - - - - )) - )} - - - {startPoint && endPoint && ( - - )} - -
- ); + )} +
+
+ ); }; export default ZoneGroup; diff --git a/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx b/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx index 123c7e3..d97e9d4 100644 --- a/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx +++ b/app/src/modules/builder/point/helpers/useAisleDragSnap.tsx @@ -16,7 +16,7 @@ export function useAislePointSnapping(point: Point) { } => { if (!CAN_SNAP) return { position: newPosition, isSnapped: false, snapSources: [] }; - const connectedPoints = getConnectedPoints(point.uuid); + const connectedPoints = getConnectedPoints(point.pointUuid); if (connectedPoints.length === 0) { return { position: newPosition, @@ -68,7 +68,7 @@ export function useAislePointSnapping(point: Point) { isSnapped, snapSources }; - }, [point.uuid, getConnectedPoints]); + }, [point.pointUuid, getConnectedPoints]); return { snapPosition }; } diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 4d61b8a..8d56085 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -13,7 +13,7 @@ export const usePointSnapping = (currentPoint: { uuid: string, pointType: string if (!currentPoint) return []; return aisles.flatMap(aisle => - aisle.points.filter(point => point.uuid !== currentPoint.uuid) + aisle.points.filter(point => point.pointUuid !== currentPoint.uuid) ); }, [aisles, currentPoint]); diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index a6c22c9..5c000f7 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -17,7 +17,7 @@ function Point({ point }: { readonly point: Point }) { const { toolMode } = useToolMode(); const { setPosition, removePoint } = useAisleStore(); const { snapPosition } = useAislePointSnapping(point); - const { checkSnapForAisle } = usePointSnapping({ uuid: point.uuid, pointType: point.pointType, position: point.position }); + const { checkSnapForAisle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { deletePointOrLine } = useDeletePointOrLine(); @@ -63,7 +63,7 @@ function Point({ point }: { readonly point: Point }) { const aisleSnappedPosition = snapPosition(newPosition); const finalSnappedPosition = checkSnapForAisle(aisleSnappedPosition.position); - setPosition(point.uuid, finalSnappedPosition.position); + setPosition(point.pointUuid, finalSnappedPosition.position); } } } @@ -76,7 +76,7 @@ function Point({ point }: { readonly point: Point }) { const handlePointClick = (point: Point) => { if (deletePointOrLine) { - const removedAisles = removePoint(point.uuid); + const removedAisles = removePoint(point.pointUuid); if (removedAisles.length > 0) { setHoveredPoint(null); console.log(removedAisles); @@ -85,7 +85,7 @@ function Point({ point }: { readonly point: Point }) { } useEffect(() => { - if (hoveredPoint && hoveredPoint.uuid !== point.uuid) { + if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) { setIsHovered(false); } }, [hoveredPoint]) @@ -102,8 +102,8 @@ function Point({ point }: { readonly point: Point }) { onDragEnd={() => { handleDragEnd(point) }} > { @@ -116,7 +116,7 @@ function Point({ point }: { readonly point: Point }) { } }} onPointerOut={() => { - if (hoveredPoint && hoveredPoint.uuid === point.uuid) { + if (hoveredPoint && hoveredPoint.pointUuid === point.pointUuid) { setHoveredPoint(null); } setIsHovered(false) diff --git a/app/src/store/builder/useAisleStore.ts b/app/src/store/builder/useAisleStore.ts index 71197c2..f379e35 100644 --- a/app/src/store/builder/useAisleStore.ts +++ b/app/src/store/builder/useAisleStore.ts @@ -30,7 +30,7 @@ interface AisleStore { ) => void; setArcAisleWidth: (aisleUuid: string, width: number) => void; setCircleAisleWidth: (aisleUuid: string, width: number) => void; - setJunctionAisleWidth: (aisleUuid: string, width: number) => void; + setJunctionAisleProperties: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void; getAisleById: (uuid: string) => Aisle | undefined; getAislePointById: (uuid: string) => Point | undefined; @@ -51,21 +51,21 @@ export const useAisleStore = create()( }), updateAisle: (uuid, updated) => set((state) => { - const aisle = state.aisles.find((a) => a.uuid === uuid); + const aisle = state.aisles.find((a) => a.aisleUuid === uuid); if (aisle) { Object.assign(aisle, updated); } }), removeAisle: (uuid) => set((state) => { - state.aisles = state.aisles.filter((a) => a.uuid !== uuid); + state.aisles = state.aisles.filter((a) => a.aisleUuid !== uuid); }), removePoint: (uuid) => { const removedAisles: Aisle[] = []; set((state) => { state.aisles = state.aisles.filter((aisle) => { - const hasPoint = aisle.points.some((point) => point.uuid === uuid); + const hasPoint = aisle.points.some((point) => point.pointUuid === uuid); if (hasPoint) { removedAisles.push(JSON.parse(JSON.stringify(aisle))); return false; @@ -79,7 +79,7 @@ export const useAisleStore = create()( setPosition: (pointUuid, position) => set((state) => { for (const aisle of state.aisles) { - const point = aisle.points.find(p => p.uuid === pointUuid); + const point = aisle.points.find(p => p.pointUuid === pointUuid); if (point) { point.position = position; } @@ -88,7 +88,7 @@ export const useAisleStore = create()( setLayer: (pointUuid, layer) => set((state) => { for (const aisle of state.aisles) { - const point = aisle.points.find(p => p.uuid === pointUuid); + const point = aisle.points.find(p => p.pointUuid === pointUuid); if (point) { point.layer = layer; } @@ -96,7 +96,7 @@ export const useAisleStore = create()( }), setColor: (aisleUuid, color) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle) { aisle.type.aisleColor = color; } @@ -104,14 +104,14 @@ export const useAisleStore = create()( // Type-specific property setters setSolidAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'solid-aisle') { aisle.type.aisleWidth = width; } }), setDashedAisleProperties: (aisleUuid, props) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'dashed-aisle') { if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth; if (props.dashLength !== undefined) aisle.type.dashLength = props.dashLength; @@ -120,14 +120,14 @@ export const useAisleStore = create()( }), setStrippedAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'stripped-aisle') { aisle.type.aisleWidth = width; } }), setDottedAisleProperties: (aisleUuid, props) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'dotted-aisle') { if (props.dotRadius !== undefined) aisle.type.dotRadius = props.dotRadius; if (props.gapLength !== undefined) aisle.type.gapLength = props.gapLength; @@ -135,14 +135,14 @@ export const useAisleStore = create()( }), setArrowAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'arrow-aisle') { aisle.type.aisleWidth = width; } }), setArrowsAisleProperties: (aisleUuid, props) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'arrows-aisle') { if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth; if (props.aisleLength !== undefined) aisle.type.aisleLength = props.aisleLength; @@ -151,33 +151,34 @@ export const useAisleStore = create()( }), setArcAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'arc-aisle') { aisle.type.aisleWidth = width; } }), setCircleAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'circle-aisle') { aisle.type.aisleWidth = width; } }), - setJunctionAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.uuid === aisleUuid); + setJunctionAisleProperties: (aisleUuid, props) => set((state) => { + const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'junction-aisle') { - aisle.type.aisleWidth = width; + if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth; + if (props.isFlipped !== undefined) aisle.type.isFlipped = props.isFlipped; } }), getAisleById: (uuid) => { - return get().aisles.find((a) => a.uuid === uuid); + return get().aisles.find((a) => a.aisleUuid === uuid); }, getAislePointById: (uuid) => { for (const aisle of get().aisles) { - const point = aisle.points.find(p => p.uuid === uuid); + const point = aisle.points.find(p => p.pointUuid === uuid); if (point) { return point; } @@ -189,8 +190,8 @@ export const useAisleStore = create()( const connected: Point[] = []; for (const aisle of get().aisles) { for (const point of aisle.points) { - if (point.uuid === uuid) { - connected.push(...aisle.points.filter(p => p.uuid !== uuid)); + if (point.pointUuid === uuid) { + connected.push(...aisle.points.filter(p => p.pointUuid !== uuid)); } } } @@ -198,7 +199,7 @@ export const useAisleStore = create()( }, getAisleType: (uuid: string) => { - const aisle = get().aisles.find(a => a.uuid === uuid); + const aisle = get().aisles.find(a => a.aisleUuid === uuid); return aisle?.type as T | undefined; }, })) diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index dc3524e..8b209dc 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -25,6 +25,9 @@ interface BuilderState { // Arrows aisle properties aisleLength: number; + // Junction aisle properties + isFlipped: boolean; + // Setters for common properties setHoveredPoint: (point: Point | null) => void; @@ -47,6 +50,9 @@ interface BuilderState { // Setters for arrows aisle setAisleLength: (length: number) => void; + // Setters for junction aisle + setIsFlipped: (isFlipped: boolean) => void; + // Batch setters setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void; setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void; @@ -71,6 +77,7 @@ export const useBuilderStore = create()( gapLength: 0.3, dotRadius: 0.1, aisleLength: 0.6, + isFlipped: false, // Individual setters @@ -133,6 +140,11 @@ export const useBuilderStore = create()( state.aisleLength = length; }); }, + setIsFlipped: (isFlipped) => { + set((state) => { + state.isFlipped = isFlipped; + }); + }, // Batch setters setDashedAisleProperties: (width, dashLength, gapLength) => { diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index b9f7616..c43805c 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -34,7 +34,7 @@ type Assets = Asset[]; type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone'; interface Point { - uuid: string; + pointUuid: string; pointType: PointTypes; position: [number, number, number]; layer: number; @@ -102,12 +102,13 @@ interface JunctionAisle { aisleType: 'junction-aisle'; aisleColor: AisleColors; aisleWidth: number; + isFlipped: boolean; } type AisleType = SolidAisle | DashedAisle | StrippedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle; interface Aisle { - uuid: string; + aisleUuid: string; points: [Point, Point]; type: AisleType; } -- 2.40.1 From cba9edd7c47e8164cb7f43493efa5c70a4e70501 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 3 Jun 2025 14:45:17 +0530 Subject: [PATCH 11/21] refactor: Update aisle types and properties, integrate arc-aisle handling --- .../properties/AisleProperties.tsx | 4 +- .../Instances/instance/aisleInstance.tsx | 5 + .../instance/aisleTypes/arcAisle.tsx | 103 ++++++++++++++++++ .../aisle/aisleCreator/aisleCreator.tsx | 37 +++---- .../aisle/aisleCreator/referenceAisle.tsx | 88 ++++++++++++++- .../selectionControls/boundingBoxHelper.tsx | 21 +++- .../selectionControls/selectionControls.tsx | 2 +- app/src/store/builder/useAisleStore.ts | 16 +-- app/src/types/builderTypes.d.ts | 9 +- 9 files changed, 235 insertions(+), 50 deletions(-) create mode 100644 app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx index a613699..644aad2 100644 --- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -194,7 +194,7 @@ const AisleProperties: React.FC = () => { } ); - case 'junction-aisle': + case 'junction-aisle': case 'arc-aisle': return ( <> {aisleType && @@ -206,7 +206,7 @@ const AisleProperties: React.FC = () => { /> } - ) + ); default: return null; } diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx index c8ecdd7..181d926 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleInstance.tsx @@ -1,3 +1,4 @@ +import ArcAisle from './aisleTypes/arcAisle'; import ArrowAisle from './aisleTypes/arrowAisle'; import ArrowsAisle from './aisleTypes/arrowsAisle'; import CircleAisle from './aisleTypes/circleAisle'; @@ -37,6 +38,10 @@ function AisleInstance({ aisle }: { readonly aisle: Aisle }) { {aisle.type.aisleType === 'junction-aisle' && ( )} + + {aisle.type.aisleType === 'arc-aisle' && ( + + )} ); } diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx new file mode 100644 index 0000000..824938d --- /dev/null +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/arcAisle.tsx @@ -0,0 +1,103 @@ +import * as THREE from 'three'; +import { useMemo, useRef } from 'react'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../../types/world/worldConstants'; +import { useToolMode } from '../../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../../store/builder/useBuilderStore'; + +function ArcAisle({ aisle }: { readonly aisle: Aisle }) { + const aisleRef = useRef(null); + const { toolMode } = useToolMode(); + const { setSelectedAisle, hoveredPoint } = useBuilderStore(); + + const arc = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.5; + const isFlipped = aisle.type.isFlipped || false; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + if (!isFlipped) perpendicular.negate(); + + const arcHeight = length * 0.25; + const midPoint = new THREE.Vector3().lerpVectors(start, end, 0.5); + const controlPoint = new THREE.Vector3().copy(midPoint).addScaledVector(perpendicular, arcHeight); + + const widthOffset = perpendicular.clone().multiplyScalar(width / 2); + + const p1 = new THREE.Vector3().copy(start).add(widthOffset); + const p2 = new THREE.Vector3().copy(end).add(widthOffset); + const p3 = new THREE.Vector3().copy(end).sub(widthOffset); + const p4 = new THREE.Vector3().copy(start).sub(widthOffset); + + const shape = new THREE.Shape(); + shape.moveTo(p1.x, p1.z); + + shape.quadraticCurveTo( + controlPoint.x + widthOffset.x, + controlPoint.z + widthOffset.z, + p2.x, p2.z + ); + + shape.lineTo(p3.x, p3.z); + + shape.quadraticCurveTo( + controlPoint.x - widthOffset.x, + controlPoint.z - widthOffset.z, + p4.x, p4.z + ); + + shape.lineTo(p1.x, p1.z); + + return { + shape, + position: new THREE.Vector3(0, 0, 0), + rotationY: 0 + }; + }, [aisle]); + + const handleClick = () => { + if (toolMode === 'move' && !hoveredPoint) { + setSelectedAisle(aisleRef.current); + } + } + + if (!arc) return null; + + return ( + { + setSelectedAisle(null); + }} + > + + + + + ); +} + +export default ArcAisle; \ No newline at end of file diff --git a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx index dca5654..d4a4007 100644 --- a/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/aisleCreator.tsx @@ -118,24 +118,6 @@ function AisleCreator() { addAisle(aisle); setTempPoints([newPoint]); } - } else if (aisleType === 'stripped-aisle') { - - if (tempPoints.length === 0) { - setTempPoints([newPoint]); - setIsCreating(true); - } else { - const aisle: Aisle = { - aisleUuid: THREE.MathUtils.generateUUID(), - points: [tempPoints[0], newPoint], - type: { - aisleType: 'stripped-aisle', - aisleColor: aisleColor, - aisleWidth: aisleWidth - } - }; - addAisle(aisle); - setTempPoints([newPoint]); - } } else if (aisleType === 'dotted-aisle') { if (tempPoints.length === 0) { @@ -194,7 +176,24 @@ function AisleCreator() { setTempPoints([newPoint]); } } else if (aisleType === 'arc-aisle') { - console.log('Creating arc-aisle'); + + if (tempPoints.length === 0) { + setTempPoints([newPoint]); + setIsCreating(true); + } else { + const aisle: Aisle = { + aisleUuid: THREE.MathUtils.generateUUID(), + points: [tempPoints[0], newPoint], + type: { + aisleType: 'arc-aisle', + aisleColor: aisleColor, + aisleWidth: aisleWidth, + isFlipped: isFlipped + } + }; + addAisle(aisle); + setTempPoints([newPoint]); + } } else if (aisleType === 'circle-aisle') { if (tempPoints.length === 0) { diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx index 5bb18fd..5f40ca4 100644 --- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -58,7 +58,7 @@ function ReferenceAisle({ tempPoints }: Readonly) { if (!finalPosition.current) return; - if (aisleType === 'solid-aisle' || aisleType === 'stripped-aisle') { + if (aisleType === 'solid-aisle') { setTempAisle({ aisleUuid: 'temp-aisle', points: [ @@ -153,9 +153,7 @@ function ReferenceAisle({ tempPoints }: Readonly) { gapLength: gapLength } }); - } else if (aisleType === 'arc-aisle') { - console.log(); - } else if (aisleType === 'junction-aisle') { + } else if (aisleType === 'junction-aisle' || aisleType === 'arc-aisle') { setTempAisle({ aisleUuid: 'temp-aisle', points: [ @@ -203,6 +201,8 @@ function ReferenceAisle({ tempPoints }: Readonly) { return ; case 'junction-aisle': return ; + case 'arc-aisle': + return default: return null; } @@ -211,7 +211,6 @@ function ReferenceAisle({ tempPoints }: Readonly) { const textPosition = new THREE.Vector3().addVectors(new THREE.Vector3(...tempAisle.points[0].position), new THREE.Vector3(...tempAisle.points[1].position)).divideScalar(2); const distance = new THREE.Vector3(...tempAisle.points[0].position).distanceTo(new THREE.Vector3(...tempAisle.points[1].position)); - const rendertext = () => { return ( <> @@ -705,4 +704,83 @@ function JunctionAisle({ aisle }: { readonly aisle: Aisle }) { ))} ); +} + +function ArcAisle({ aisle }: { readonly aisle: Aisle }) { + const arc = useMemo(() => { + if (aisle.points.length < 2 || aisle.type.aisleType !== 'arc-aisle') return null; + + const start = new THREE.Vector3(...aisle.points[0].position); + const end = new THREE.Vector3(...aisle.points[1].position); + const width = aisle.type.aisleWidth || 0.5; + const isFlipped = aisle.type.isFlipped || false; + + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const perpendicular = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); + if (!isFlipped) perpendicular.negate(); + + const arcHeight = length * 0.25; + const midPoint = new THREE.Vector3().lerpVectors(start, end, 0.5); + const controlPoint = new THREE.Vector3().copy(midPoint).addScaledVector(perpendicular, arcHeight); + + const widthOffset = perpendicular.clone().multiplyScalar(width / 2); + + const p1 = new THREE.Vector3().copy(start).add(widthOffset); + const p2 = new THREE.Vector3().copy(end).add(widthOffset); + const p3 = new THREE.Vector3().copy(end).sub(widthOffset); + const p4 = new THREE.Vector3().copy(start).sub(widthOffset); + + const shape = new THREE.Shape(); + shape.moveTo(p1.x, p1.z); + + shape.quadraticCurveTo( + controlPoint.x + widthOffset.x, + controlPoint.z + widthOffset.z, + p2.x, p2.z + ); + + shape.lineTo(p3.x, p3.z); + + shape.quadraticCurveTo( + controlPoint.x - widthOffset.x, + controlPoint.z - widthOffset.z, + p4.x, p4.z + ); + + shape.lineTo(p1.x, p1.z); + + return { + shape, + position: new THREE.Vector3(0, 0, 0), + rotationY: 0 + }; + }, [aisle]); + + + if (!arc) return null; + + return ( + + + + + + ); } \ No newline at end of file diff --git a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx index 32fcce7..05b43c6 100644 --- a/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx +++ b/app/src/modules/scene/controls/selectionControls/boundingBoxHelper.tsx @@ -33,8 +33,13 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => if (selectedAssets.length === 0) return []; if (isPerAsset) { - return selectedAssets.map((obj: any) => { - const box = new THREE.Box3().setFromObject(obj.clone()); + return selectedAssets.map((obj: THREE.Object3D) => { + const position = obj.position; + const rotation = obj.getWorldQuaternion(new THREE.Quaternion()); + const clone = obj.clone(); + clone.position.set(0, 0, 0); + clone.rotation.set(0, 0, 0); + const box = new THREE.Box3().setFromObject(clone); const size = new THREE.Vector3(); const center = new THREE.Vector3(); box.getSize(size); @@ -46,7 +51,8 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => return { points: getBoxLines(min, max), - position: center.toArray(), + position: [position.x, center.y, position.z], + rotation: rotation.toArray(), size: size.toArray(), }; }); @@ -66,6 +72,7 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => { points: getBoxLines(min, max), position: center.toArray(), + rotation: [0, 0, 0, 1], size: size.toArray(), }, ]; @@ -75,7 +82,10 @@ const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => return ( <> {boxes.map((box: any, index: number) => ( - + color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"} lineWidth={2.7} segments + position={[box.position[0], 0, box.position[2]]} + quaternion={new THREE.Quaternion(...box.rotation)} /> diff --git a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx index 0c158a9..d0954e4 100644 --- a/app/src/modules/scene/controls/selectionControls/selectionControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/selectionControls.tsx @@ -309,7 +309,7 @@ const SelectionControls: React.FC = () => { <> - + diff --git a/app/src/store/builder/useAisleStore.ts b/app/src/store/builder/useAisleStore.ts index f379e35..bf05851 100644 --- a/app/src/store/builder/useAisleStore.ts +++ b/app/src/store/builder/useAisleStore.ts @@ -18,7 +18,6 @@ interface AisleStore { aisleUuid: string, props: { aisleWidth?: number; dashLength?: number; gapLength?: number } ) => void; - setStrippedAisleWidth: (aisleUuid: string, width: number) => void; setDottedAisleProperties: ( aisleUuid: string, props: { dotRadius?: number; gapLength?: number } @@ -28,7 +27,7 @@ interface AisleStore { aisleUuid: string, props: { aisleWidth?: number; aisleLength?: number; gapLength?: number } ) => void; - setArcAisleWidth: (aisleUuid: string, width: number) => void; + setArcAisleWidth: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void; setCircleAisleWidth: (aisleUuid: string, width: number) => void; setJunctionAisleProperties: (aisleUuid: string, props: { aisleWidth?: number; isFlipped: boolean; }) => void; @@ -73,7 +72,6 @@ export const useAisleStore = create()( return true; }); }); - console.log('removedAisles: ', removedAisles); return removedAisles; }, @@ -119,13 +117,6 @@ export const useAisleStore = create()( } }), - setStrippedAisleWidth: (aisleUuid, width) => set((state) => { - const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); - if (aisle && aisle.type.aisleType === 'stripped-aisle') { - aisle.type.aisleWidth = width; - } - }), - setDottedAisleProperties: (aisleUuid, props) => set((state) => { const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'dotted-aisle') { @@ -150,10 +141,11 @@ export const useAisleStore = create()( } }), - setArcAisleWidth: (aisleUuid, width) => set((state) => { + setArcAisleWidth: (aisleUuid, props) => set((state) => { const aisle = state.aisles.find(a => a.aisleUuid === aisleUuid); if (aisle && aisle.type.aisleType === 'arc-aisle') { - aisle.type.aisleWidth = width; + if (props.aisleWidth !== undefined) aisle.type.aisleWidth = props.aisleWidth; + if (props.isFlipped !== undefined) aisle.type.isFlipped = props.isFlipped; } }), diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index c43805c..c796069 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -59,12 +59,6 @@ interface DashedAisle { gapLength: number; } -interface StrippedAisle { - aisleType: 'stripped-aisle'; - aisleColor: AisleColors; - aisleWidth: number; -} - interface DottedAisle { aisleType: 'dotted-aisle'; aisleColor: AisleColors; @@ -90,6 +84,7 @@ interface ArcAisle { aisleType: 'arc-aisle'; aisleColor: AisleColors; aisleWidth: number; + isFlipped: boolean; } interface CircleAisle { @@ -105,7 +100,7 @@ interface JunctionAisle { isFlipped: boolean; } -type AisleType = SolidAisle | DashedAisle | StrippedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle; +type AisleType = SolidAisle | DashedAisle | DottedAisle | ArrowAisle | ArrowsAisle | ArcAisle | CircleAisle | JunctionAisle; interface Aisle { aisleUuid: string; -- 2.40.1 From 49ac22607845cd7682057fa3ca18d70823e6060a Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 3 Jun 2025 16:33:15 +0530 Subject: [PATCH 12/21] refactor: Update TextureItem interface and aisle color identifiers for consistency --- .../properties/AisleProperties.tsx | 18 +++++++++-------- .../instance/aisleTypes/solidAisle.tsx | 1 - .../aisle/aisleCreator/referenceAisle.tsx | 6 ++---- app/src/modules/builder/groups/zoneGroup.tsx | 2 -- app/src/types/builderTypes.d.ts | 20 ++++++++++++++++++- 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx index 644aad2..c343805 100644 --- a/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AisleProperties.tsx @@ -15,8 +15,8 @@ import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import InputToggle from "../../../ui/inputs/InputToggle"; interface TextureItem { - color: AisleColors; - id: string; + color: string; + id: AisleColors; brief: string; texture: string; } @@ -28,14 +28,14 @@ const AisleProperties: React.FC = () => { const { aisleType, aisleWidth, aisleColor, dashLength, gapLength, dotRadius, aisleLength, isFlipped, setAisleType, setAisleColor, setAisleWidth, setDashLength, setGapLength, setDotRadius, setAisleLength, setIsFlipped } = useBuilderStore(); const aisleTextureList: TextureItem[] = [ - { color: "yellow", id: "yellow1", brief: "pedestrian walkways", texture: "" }, + { color: "yellow", id: "yellow", brief: "pedestrian walkways", texture: "" }, { color: "gray", id: "gray", brief: "basic", texture: "" }, - { color: "green", id: "green1", brief: "pedestrian walkways", texture: "" }, + { color: "green", id: "green", brief: "pedestrian walkways", texture: "" }, { color: "orange", id: "orange", brief: "material flow", texture: "" }, { color: "blue", id: "blue", brief: "vehicle paths", texture: "" }, { color: "purple", id: "purple", brief: "material flow", texture: "" }, { color: "red", id: "red", brief: "safety zone", texture: "" }, - { color: "bright green", id: "bright-green", brief: "safety zone", texture: "" }, + { color: "bright green", id: "#66FF00", brief: "safety zone", texture: "" }, { color: "yellow-black", id: "yellow-black", brief: "utility aisles", texture: "" }, { color: "white-black", id: "white-black", brief: "utility aisles", texture: "" }, ]; @@ -166,7 +166,8 @@ const AisleProperties: React.FC = () => { step={0.1} max={2} onChange={handleGapLengthChange} - /> + /> + } ); @@ -190,7 +191,8 @@ const AisleProperties: React.FC = () => { step={0.1} max={2} onChange={handleGapLengthChange} - /> + /> + } ); @@ -280,7 +282,7 @@ const AisleProperties: React.FC = () => { key={val.id} title={val.brief || val.id} className={`aisle-list ${aisleColor === val.color ? "selected" : ""}`} - onClick={() => setAisleColor(val.color)} + onClick={() => setAisleColor(val.id)} aria-pressed={aisleColor === val.id} >
{val.texture}
diff --git a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx index af4b772..dd4d700 100644 --- a/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx +++ b/app/src/modules/builder/aisle/Instances/instance/aisleTypes/solidAisle.tsx @@ -9,7 +9,6 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) { const aisleRef = useRef(null); const { toolMode } = useToolMode(); const { setSelectedAisle, hoveredPoint } = useBuilderStore(); - const shape = useMemo(() => { if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') return null; diff --git a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx index 5f40ca4..149233b 100644 --- a/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx +++ b/app/src/modules/builder/aisle/aisleCreator/referenceAisle.tsx @@ -251,6 +251,7 @@ function ReferenceAisle({ tempPoints }: Readonly) { export default ReferenceAisle; function SolidAisle({ aisle }: { readonly aisle: Aisle }) { + const shape = useMemo(() => { if (aisle.points.length < 2 || aisle.type.aisleType !== 'solid-aisle') return null; @@ -288,10 +289,7 @@ function SolidAisle({ aisle }: { readonly aisle: Aisle }) { receiveShadow castShadow > - +
); diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 349fe07..443a400 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -91,7 +91,6 @@ const ZoneGroup: React.FC = () => { layer: zone.layer, })); - console.log('fetchedZones: ', fetchedZones); setZones(fetchedZones); const fetchedPoints = data.data.flatMap((zone: any) => @@ -110,7 +109,6 @@ const ZoneGroup: React.FC = () => { }, []); useEffect(() => { - console.log('zones: ', zones); localStorage.setItem("zones", JSON.stringify(zones)); }, [zones]); diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index c796069..19d413e 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -1,3 +1,5 @@ +// Asset + interface Asset { modelUuid: string; modelName: string; @@ -31,6 +33,8 @@ interface Asset { type Assets = Asset[]; +// Point + type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone'; interface Point { @@ -41,9 +45,23 @@ interface Point { } +// Wall + +interface Wall { + wallUuid: string; + points: [Point, Point]; + outSideMaterial: string; + inSideMaterial: string; + thickness: number; + height: number; +} + + +// Aisle + type AisleTypes = 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; -type AisleColors = 'gray' | 'yellow' | 'green' | 'orange' | 'blue' | 'purple' | 'red' | 'bright green' | 'yellow-black' | 'white-black' +type AisleColors = 'gray' | 'yellow' | 'green' | 'orange' | 'blue' | 'purple' | 'red' | '#66FF00' | 'yellow-black' | 'white-black' interface SolidAisle { aisleType: 'solid-aisle'; -- 2.40.1 From 5ba745727659e36a7be4c672985616dfe6285054 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 4 Jun 2025 09:11:11 +0530 Subject: [PATCH 13/21] Enhance DashboardCard component: add createdAt prop and implement relative time display; create ProjectSocketDev component for socket event handling. --- .../components/Dashboard/DashboardCard.tsx | 52 ++++++--- .../Dashboard/socket/projectSocket.dev.tsx | 102 ++++++++++++++++++ .../utils/shortcutkeys/detectModifierKeys.ts | 1 + 3 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 app/src/components/Dashboard/socket/projectSocket.dev.tsx diff --git a/app/src/components/Dashboard/DashboardCard.tsx b/app/src/components/Dashboard/DashboardCard.tsx index 5d11950..63815de 100644 --- a/app/src/components/Dashboard/DashboardCard.tsx +++ b/app/src/components/Dashboard/DashboardCard.tsx @@ -6,16 +6,13 @@ import { useProjectName, useSocketStore } from "../../store/builder/store"; import { viewProject } from "../../services/dashboard/viewProject"; import OuterClick from "../../utils/outerClick"; import { KebabIcon } from "../icons/ExportCommonIcons"; -import darkThemeImage from "../../assets/image/darkThemeProject.png"; -import lightThemeImage from "../../assets/image/lightThemeProject.png"; -import { updateProject } from "../../services/dashboard/updateProject"; import { getAllProjects } from "../../services/dashboard/getAllProjects"; -import { duplicateProject } from "../../services/dashboard/duplicateProject"; interface DashBoardCardProps { projectName: string; thumbnail: any; projectId: string; + createdAt?: string handleDeleteProject?: (projectId: string) => Promise; handleTrashDeleteProject?: (projectId: string) => Promise; handleRestoreProject?: (projectId: string) => Promise; @@ -24,6 +21,8 @@ interface DashBoardCardProps { active?: string; setIsSearchActive?: React.Dispatch>; } +type RelativeTimeFormatUnit = any + const DashboardCard: React.FC = ({ projectName, @@ -33,9 +32,9 @@ const DashboardCard: React.FC = ({ handleDeleteProject, handleRestoreProject, handleTrashDeleteProject, - setIsSearchActive, handleDuplicateWorkspaceProject, - handleDuplicateRecentProject + handleDuplicateRecentProject, + createdAt }) => { const navigate = useNavigate(); const { setProjectName } = useProjectName(); @@ -44,10 +43,8 @@ const DashboardCard: React.FC = ({ const [renameValue, setRenameValue] = useState(projectName); const [isRenaming, setIsRenaming] = useState(false); const { projectSocket } = useSocketStore(); - const kebabRef = useRef(null); const savedTheme = localStorage.getItem("theme") ?? "light"; - const navigateToProject = async (e: any) => { if (active && active == "trash") return try { @@ -68,9 +65,7 @@ const DashboardCard: React.FC = ({ await handleDeleteProject(projectId); } else if (handleTrashDeleteProject) { - console.log('projectId:dashboard ', projectId); - // await handleTrashDeleteProject(projectId); - handleTrashDeleteProject(projectId); + await handleTrashDeleteProject(projectId); } break; case "restore": @@ -146,7 +141,7 @@ const DashboardCard: React.FC = ({ setMenuVisible: () => setIsKebabOpen(false), }); const handleProjectName = async (projectName: string) => { - setProjectName(projectName); + // setProjectName(projectName); setRenameValue(projectName) if (!projectId) return // localStorage.setItem("projectName", newName); @@ -190,6 +185,34 @@ const DashboardCard: React.FC = ({ } }; + function getRelativeTime(dateString: string): string { + const date = new Date(dateString); + const now = new Date(); + const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); + + const intervals: Record = { + year: 31536000, + month: 2592000, + week: 604800, + day: 86400, + hour: 3600, + minute: 60, + second: 1, + }; + + const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); + + for (const key in intervals) { + const unit = key as RelativeTimeFormatUnit; + const diff = Math.floor(diffInSeconds / intervals[unit]); + if (diff >= 1) { + return rtf.format(-diff, unit); + } + } + return 'just now'; + } + + return ( - ))} + {["rename", "delete", "duplicate", "open in new tab"].map( + (option) => ( + + ) + )} )} {isKebabOpen && active && active == "trash" && ( - < div className="kebab-options-wrapper"> +
{["restore", "delete"].map((option) => ( ))}
- ) - } - + )} + ); }; -export default DashboardCard; +export default DashboardCard; \ No newline at end of file diff --git a/app/src/components/Dashboard/DashboardHome.tsx b/app/src/components/Dashboard/DashboardHome.tsx index 8da0571..2627a65 100644 --- a/app/src/components/Dashboard/DashboardHome.tsx +++ b/app/src/components/Dashboard/DashboardHome.tsx @@ -7,7 +7,7 @@ import { useSocketStore } from "../../store/builder/store"; import { recentlyViewed } from "../../services/dashboard/recentlyViewed"; import { searchProject } from "../../services/dashboard/searchProjects"; import { deleteProject } from "../../services/dashboard/deleteProject"; -import { handleDuplicateProjects } from "./functions/handleDuplicateProject"; +import ProjectSocketRes from "./socket/projectSocketRes.dev"; interface Project { _id: string; @@ -15,6 +15,7 @@ interface Project { thumbnail: string; createdBy: string; projectUuid?: string; + createdAt: string; } interface RecentProjectsData { @@ -26,11 +27,13 @@ const DashboardHome: React.FC = () => { const [isSearchActive, setIsSearchActive] = useState(false); const { userId, organization } = getUserData(); const { projectSocket } = useSocketStore(); + const [recentDuplicateData, setRecentDuplicateData] = useState({}); + console.log("duplicateData: ", recentDuplicateData); const fetchRecentProjects = async () => { try { const projects = await recentlyViewed(organization, userId); - console.log('RecentlyViewed: ', projects); + console.log("RecentlyViewed: ", projects); if (JSON.stringify(projects) !== JSON.stringify(recentProjects)) { setRecentProjects(projects); @@ -50,13 +53,12 @@ const DashboardHome: React.FC = () => { userId, inputValue ); - console.log('filterRecentProcess: ', filterRecentProcess); setIsSearchActive(true); setRecentProjects(filterRecentProcess.message ? {} : filterRecentProcess); }; const handleDeleteProject = async (projectId: any) => { - console.log('projectId:delete ', projectId); + console.log("projectId:delete ", projectId); try { //API for delete project // const deletedProject = await deleteProject( @@ -74,12 +76,6 @@ const DashboardHome: React.FC = () => { }; if (projectSocket) { - const handleResponse = (data: any) => { - console.log("Project add response:", data); - projectSocket.off("v1-project:response:delete", handleResponse); - }; - - projectSocket.on("v1-project:response:delete", handleResponse); projectSocket.emit("v1:project:delete", deleteProject); } @@ -101,20 +97,20 @@ const DashboardHome: React.FC = () => { } }; - const handleDuplicateRecentProject = async (projectId: string, projectName: string, thumbnail: string) => { - - await handleDuplicateProjects({ + const handleDuplicateRecentProject = async ( + projectId: string, + projectName: string, + thumbnail: string + ) => { + const duplicateRecentProjectData = { userId, - organization, - projectId, - projectName, - projectSocket, thumbnail, - setRecentProjects, - setIsSearchActive - }); - - } + organization, + projectUuid: projectId, + projectName, + }; + projectSocket.emit("v1:project:Duplicate", duplicateRecentProjectData); + }; const renderProjects = () => { const projectList = recentProjects[Object.keys(recentProjects)[0]]; @@ -123,16 +119,21 @@ const DashboardHome: React.FC = () => { return
No recent projects found
; } - return projectList && projectList.map((project) => ( - - )); + return ( + projectList && + projectList.map((project) => ( + + )) + ); }; useEffect(() => { @@ -147,17 +148,19 @@ const DashboardHome: React.FC = () => { page="home" handleRecentProjectSearch={handleRecentProjectSearch} /> - -

Recents

{renderProjects()}
+ {recentDuplicateData && Object.keys(recentDuplicateData).length > 0 && ( + + )} ); }; -export default DashboardHome; - - +export default DashboardHome; \ No newline at end of file diff --git a/app/src/components/Dashboard/DashboardProjects.tsx b/app/src/components/Dashboard/DashboardProjects.tsx index 2199f19..98a79f7 100644 --- a/app/src/components/Dashboard/DashboardProjects.tsx +++ b/app/src/components/Dashboard/DashboardProjects.tsx @@ -6,7 +6,7 @@ import { useSocketStore } from "../../store/builder/store"; import { getAllProjects } from "../../services/dashboard/getAllProjects"; import { searchProject } from "../../services/dashboard/searchProjects"; import { deleteProject } from "../../services/dashboard/deleteProject"; -import { handleDuplicateProjects } from "./functions/handleDuplicateProject"; +import ProjectSocketRes from "./socket/projectSocketRes.dev"; interface Project { _id: string; @@ -14,6 +14,7 @@ interface Project { thumbnail: string; createdBy: string; projectUuid?: string; + createdAt: string; } interface WorkspaceProjects { @@ -24,9 +25,9 @@ const DashboardProjects: React.FC = () => { const [workspaceProjects, setWorkspaceProjects] = useState( {} ); - console.log('workspaceProjects: ', workspaceProjects); + const [projectDuplicateData, setProjectDuplicateData] = useState({}); + console.log("projectDuplicateData: ", projectDuplicateData); const [isSearchActive, setIsSearchActive] = useState(false); - const [activeFolder, setActiveFolder] = useState("myProjects"); const { projectSocket } = useSocketStore(); const { userId, organization } = getUserData(); @@ -50,11 +51,7 @@ const DashboardProjects: React.FC = () => { } if (!setWorkspaceProjects || !setIsSearchActive) return; - const searchedProject = await searchProject( - organization, - userId, - inputValue - ); + const searchedProject = await searchProject(organization, userId, inputValue); setIsSearchActive(true); setWorkspaceProjects(searchedProject.message ? {} : searchedProject); }; @@ -75,13 +72,6 @@ const DashboardProjects: React.FC = () => { //socket for deleting the project if (projectSocket) { - const handleResponse = (data: any) => { - console.log("Project add response:", data); - projectSocket.off("v1-project:response:delete", handleResponse); // Clean up - }; - - projectSocket.on("v1-project:response:delete", handleResponse); - projectSocket.emit("v1:project:delete", deleteProjects); } else { console.error("Socket is not connected."); @@ -104,20 +94,30 @@ const DashboardProjects: React.FC = () => { } }; - const handleDuplicateWorkspaceProject = async (projectId: string, projectName: string, thumbnail: string) => { - - await handleDuplicateProjects({ + const handleDuplicateWorkspaceProject = async ( + projectId: string, + projectName: string, + thumbnail: string + ) => { + // await handleDuplicateProjects({ + // userId, + // organization, + // projectId, + // projectName, + // projectSocket, + // thumbnail, + // setWorkspaceProjects, + // setIsSearchActive + // }); + const duplicateProjectData = { userId, - organization, - projectId, - projectName, - projectSocket, thumbnail, - setWorkspaceProjects, - setIsSearchActive - }); - - } + organization, + projectUuid: projectId, + projectName, + }; + projectSocket.emit("v1:project:Duplicate", duplicateProjectData); + }; const renderProjects = () => { if (activeFolder !== "myProjects") return null; @@ -134,9 +134,11 @@ const DashboardProjects: React.FC = () => { projectName={project.projectName} thumbnail={project.thumbnail} projectId={project._id} + createdAt={project.createdAt} handleDeleteProject={handleDeleteProject} setIsSearchActive={setIsSearchActive} handleDuplicateWorkspaceProject={handleDuplicateWorkspaceProject} + setProjectDuplicateData={setProjectDuplicateData} /> )); }; @@ -170,9 +172,15 @@ const DashboardProjects: React.FC = () => {
{renderProjects()}
+ {projectDuplicateData && Object.keys(projectDuplicateData).length > 0 && ( + + )} ); }; -export default DashboardProjects; +export default DashboardProjects; \ No newline at end of file diff --git a/app/src/components/Dashboard/DashboardTrash.tsx b/app/src/components/Dashboard/DashboardTrash.tsx index 1aeae11..e1329fc 100644 --- a/app/src/components/Dashboard/DashboardTrash.tsx +++ b/app/src/components/Dashboard/DashboardTrash.tsx @@ -14,6 +14,7 @@ interface Project { thumbnail: string; createdBy: string; projectUuid?: string; + DeletedAt: string; } interface DiscardedProjects { @@ -28,7 +29,6 @@ const DashboardTrash: React.FC = () => { const { userId, organization } = getUserData(); const { projectSocket } = useSocketStore(); - const fetchTrashProjects = async () => { try { const projects = await getTrash(organization); @@ -40,6 +40,7 @@ const DashboardTrash: React.FC = () => { console.error("Error fetching trash projects:", error); } }; + const handleTrashSearch = async (inputValue: string) => { if (!inputValue.trim()) { setIsSearchActive(false); @@ -57,8 +58,9 @@ const DashboardTrash: React.FC = () => { filterTrashedProcess.message ? {} : filterTrashedProcess ); }; + const handleRestoreProject = async (projectId: any) => { - console.log('projectId: ', projectId); + console.log("projectId: ", projectId); try { const restoreProject = await restoreTrash(organization, projectId); // console.log('restoreProject: ', restoreProject); @@ -82,25 +84,19 @@ const DashboardTrash: React.FC = () => { console.error("Error deleting project:", error); } }; + const handleTrashDeleteProject = async (projectId: any) => { try { // const deletedProject = await deleteTrash( // organization, projectId // ); - const deleteProjectTrash = { projectId, organization, userId, }; if (projectSocket) { - const handleResponse = (data: any) => { - console.log('data:deleteTrash ', data); - projectSocket.off("v1:trash:response:delete", handleResponse); - }; - projectSocket.on("v1:trash:response:delete", handleResponse); - console.log("duplicate: ", deleteProjectTrash); projectSocket.emit("v1:trash:delete", deleteProjectTrash); } setDiscardedProjects((prevDiscardedProjects: DiscardedProjects) => { @@ -138,6 +134,7 @@ const DashboardTrash: React.FC = () => { handleRestoreProject={handleRestoreProject} handleTrashDeleteProject={handleTrashDeleteProject} active={"trash"} + createdAt={project.DeletedAt} /> )); }; @@ -160,4 +157,4 @@ const DashboardTrash: React.FC = () => { ); }; -export default DashboardTrash; +export default DashboardTrash; \ No newline at end of file diff --git a/app/src/components/Dashboard/SidePannel.tsx b/app/src/components/Dashboard/SidePannel.tsx index 4bb7f61..d1786a1 100644 --- a/app/src/components/Dashboard/SidePannel.tsx +++ b/app/src/components/Dashboard/SidePannel.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { DocumentationIcon, HelpIcon, @@ -15,33 +15,35 @@ import { SettingsIcon, TrashIcon } from "../icons/ExportCommonIcons"; import { getUserData } from "./functions/getUserData"; import { useLoadingProgress, useSocketStore } from "../../store/builder/store"; import { createProject } from "../../services/dashboard/createProject"; + interface SidePannelProps { setActiveTab: React.Dispatch>; - activeTab: string + activeTab: string; } const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { const { email, userName, userId, organization } = getUserData(); const navigate = useNavigate(); - const { loadingProgress, setLoadingProgress } = useLoadingProgress(); - const { dashBoardSocket, projectSocket } = useSocketStore(); + const { setLoadingProgress } = useLoadingProgress(); + const { projectSocket } = useSocketStore(); const savedTheme = localStorage.getItem("theme") ?? "light"; + function generateProjectId() { const randomBytes = new Uint8Array(12); crypto.getRandomValues(randomBytes); return Array.from(randomBytes, (byte) => - byte.toString(16).padStart(2, "0")).join(""); + byte.toString(16).padStart(2, "0") + ).join(""); } - const handleCreateNewProject = async () => { const token = localStorage.getItem("token"); try { const projectId = generateProjectId(); useSocketStore.getState().initializeSocket(email, organization, token); - console.log('projectId: ', projectId); + console.log("projectId: ", projectId); navigate(`/${projectId}`); - setLoadingProgress(1) + setLoadingProgress(1); //API for creating new Project // const project = await createProject( // projectId, @@ -56,18 +58,8 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { organization: organization, projectUuid: projectId, }; - // socket for creating new project - // console.log('dashBoardSocket: ', dashBoardSocket); - console.log('projectSocket: ', projectSocket); + console.log("projectSocket: ", projectSocket); if (projectSocket) { - // console.log('addProject: ', addProject); - const handleResponse = (data: any) => { - console.log('Project add response:', data); - projectSocket.off("v1-project:response:add", handleResponse); // Clean up - }; - projectSocket.on("v1-project:response:add", handleResponse); - - console.log('addProject: ', addProject); projectSocket.emit("v1:project:add", addProject); } else { console.error("Socket is not connected."); @@ -81,33 +73,76 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => {
-
{userName?.charAt(0).toUpperCase()}
-
{userName ? userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase() : "Anonymous"}
+
+ {userName?.charAt(0).toUpperCase()} +
+
+ {userName + ? userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase() + : "Anonymous"} +
-
+ New project
+
+ + New project +
-
setActiveTab("Home")}> +
setActiveTab("Home")} + > Home
-
setActiveTab("Projects")}> +
setActiveTab("Projects")} + > Projects
-
setActiveTab("Trash")}> +
setActiveTab("Trash")} + > Trash
-
setActiveTab("Tutorials")}> +
setActiveTab("Tutorials")} + > Tutorials
-
setActiveTab("Documentation")}> +
setActiveTab("Documentation")} + > Documentation
@@ -131,4 +166,4 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { ); }; -export default SidePannel; +export default SidePannel; \ No newline at end of file diff --git a/app/src/components/Dashboard/functions/handleDuplicateProject.ts b/app/src/components/Dashboard/functions/handleDuplicateProject.ts deleted file mode 100644 index c17c9a3..0000000 --- a/app/src/components/Dashboard/functions/handleDuplicateProject.ts +++ /dev/null @@ -1,117 +0,0 @@ -// import { getAllProjects } from "../../../services/dashboard/getAllProjects"; - -// interface HandleDuplicateProjectsParams { -// userId: string; -// organization: string; -// projectId: string; -// projectName: string; -// projectSocket: any; -// thumbnail: string; -// setWorkspaceProjects?: React.Dispatch>; -// setRecentProjects?: React.Dispatch>; -// setIsSearchActive: React.Dispatch>; -// } - -// export const handleDuplicateProjects = async ({ -// userId, -// organization, -// projectId, -// projectName, -// projectSocket, -// thumbnail, -// setWorkspaceProjects, -// setRecentProjects, -// setIsSearchActive, -// }: HandleDuplicateProjectsParams): Promise => { -// const duplicateProjectData = { -// userId, -// thumbnail, -// organization, -// projectUuid: projectId, -// projectName, -// }; - -// if (projectSocket) { -// const handleResponse = (data: any) => { -// console.log("Project add response:", data); -// projectSocket.off("v1-project:response:Duplicate", handleResponse); // Clean up -// }; - -// projectSocket.on("v1-project:response:Duplicate", handleResponse); -// console.log("duplicate: ", duplicateProjectData); -// projectSocket.emit("v1:project:Duplicate", duplicateProjectData); - -// const projects = await getAllProjects(userId, organization); -// console.log("projects: works", projects); -// if (setIsSearchActive) { -// if (setWorkspaceProjects) { -// setWorkspaceProjects(projects); -// } else if (setRecentProjects) { -// setRecentProjects(projects); -// } -// setIsSearchActive(false); -// } -// } -// }; - -import { getAllProjects } from "../../../services/dashboard/getAllProjects"; -import { recentlyViewed } from "../../../services/dashboard/recentlyViewed"; - -interface HandleDuplicateProjectsParams { - userId: string; - organization: string; - projectId: string; - projectName: string; - projectSocket: any; - thumbnail: string; - setWorkspaceProjects?: React.Dispatch>; - setRecentProjects?: React.Dispatch>; - setIsSearchActive: React.Dispatch>; -} - -export const handleDuplicateProjects = async ({ - userId, - organization, - projectId, - projectName, - projectSocket, - thumbnail, - setWorkspaceProjects, - setRecentProjects, - setIsSearchActive, -}: HandleDuplicateProjectsParams): Promise => { - const duplicateProjectData = { - userId, - thumbnail, - organization, - projectUuid: projectId, - projectName, - }; - - if (projectSocket) { - const handleResponse = async (data: any) => { - console.log("Project add response:", data); - - if (data?.message === "Project Duplicated successfully") { - if (setWorkspaceProjects) { - const allProjects = await getAllProjects(userId, organization); - setWorkspaceProjects(allProjects); - } else if (setRecentProjects) { - const recentProjects = await recentlyViewed(organization, userId); - console.log('recentProjects: ', recentProjects); - setRecentProjects(recentProjects); - } - - setIsSearchActive(false); - } else { - console.warn("Duplication failed or unexpected response."); - } - - projectSocket.off("v1-project:response:Duplicate", handleResponse); // Clean up - }; - - projectSocket.on("v1-project:response:Duplicate", handleResponse); - console.log("Emitting duplicate:", duplicateProjectData); - projectSocket.emit("v1:project:Duplicate", duplicateProjectData); - } -}; diff --git a/app/src/components/Dashboard/socket/projectSocket.dev.tsx b/app/src/components/Dashboard/socket/projectSocket.dev.tsx deleted file mode 100644 index 02404e7..0000000 --- a/app/src/components/Dashboard/socket/projectSocket.dev.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useEffect } from 'react'; -import { useSocketStore } from '../../../store/builder/store'; -import { getAllProjects } from '../../../services/dashboard/getAllProjects'; -import { recentlyViewed } from '../../../services/dashboard/recentlyViewed'; -import { data } from 'react-router-dom'; -interface HandleDuplicateProjectsParams { - userId: string; - organization: string; - projectId: string; - projectName: string; - projectSocket: any; - thumbnail: string; - setWorkspaceProjects?: React.Dispatch>; - setRecentProjects?: React.Dispatch>; - setIsSearchActive: React.Dispatch>; -} -const ProjectSocketDev = () => { - - const { projectSocket } = useSocketStore(); - - useEffect(() => { - - if (projectSocket) { - - projectSocket.on("v1-project:response:add", (data: any) => { - // console.log('data: ', data); - }) - projectSocket.on("v1-project:response:delete", (data: any) => { - // console.log('data: ', data) - }) - projectSocket.on("v1-project:response:update", (data: any) => { - // console.log('data: ', data); - }); - projectSocket.on("v1-project:response:Duplicate", (data: any) => { - // console.log('data: ', data); - }) - projectSocket.on("v1:trash:response:delete", (data: any) => { - // console.log('data: ', data); - }) - - } - return (() => { - projectSocket.off("v1-project:response:add"); - projectSocket.off("v1-project:response:delete"); - projectSocket.off("v1-project:response:update"); - projectSocket.off("v1-project:response:Duplicate"); - projectSocket.off("v1:trash:response:delete"); - - }) - }, [projectSocket]) - - // const handleDuplicateProjects = async ({ - // userId, - // organization, - // projectId, - // projectName, - // projectSocket, - // thumbnail, - // setWorkspaceProjects, - // setRecentProjects, - // setIsSearchActive, - // }: HandleDuplicateProjectsParams): Promise => { - // const duplicateProjectData = { - // userId, - // thumbnail, - // organization, - // projectUuid: projectId, - // projectName, - // }; - - // if (projectSocket) { - // const handleResponse = async (data: any) => { - // console.log("Project add response:", data); - - // if (data?.message === "Project Duplicated successfully") { - // if (setWorkspaceProjects) { - // const allProjects = await getAllProjects(userId, organization); - // console.log("allProjects: ", allProjects); - // setWorkspaceProjects(allProjects); - // } else if (setRecentProjects) { - // const recentProjects = await recentlyViewed(organization, userId); - // console.log("recentProjects: ", recentProjects); - // setRecentProjects(recentProjects); - // } - - // setIsSearchActive(false); - // } else { - // console.warn("Duplication failed or unexpected response."); - // } - - // projectSocket.off("v1-project:response:Duplicate", handleResponse); // Clean up - // }; - - // projectSocket.on("v1-project:response:Duplicate", handleResponse); - // console.log("Emitting duplicate:", duplicateProjectData); - - // } - // }; - return <> -} - -export default ProjectSocketDev; diff --git a/app/src/components/Dashboard/socket/projectSocketRes.dev.tsx b/app/src/components/Dashboard/socket/projectSocketRes.dev.tsx new file mode 100644 index 0000000..6ab556b --- /dev/null +++ b/app/src/components/Dashboard/socket/projectSocketRes.dev.tsx @@ -0,0 +1,88 @@ + +import React, { useEffect } from 'react'; +import { useSocketStore } from '../../../store/builder/store'; +import { getUserData } from '../functions/getUserData'; +import { getAllProjects } from '../../../services/dashboard/getAllProjects'; +import { recentlyViewed } from '../../../services/dashboard/recentlyViewed'; + +interface Project { + _id: string; + projectName: string; + thumbnail: string; + createdBy: string; + projectUuid?: string; + createdAt: string; +} + +interface ProjectsData { + [key: string]: Project[]; +} +interface ProjectSocketResProps { + setRecentProjects?: React.Dispatch>; + setWorkspaceProjects?: React.Dispatch>; + setIsSearchActive?: React.Dispatch>; +} + +const ProjectSocketRes = ({ + setRecentProjects, + setWorkspaceProjects, + setIsSearchActive, +}: ProjectSocketResProps) => { + const { projectSocket } = useSocketStore(); + const { userId, organization } = getUserData(); + + useEffect(() => { + if (!projectSocket) return; + + const handleAdd = (data: any) => { + // console.log('Add:', data); + }; + + const handleDelete = (data: any) => { + // console.log('Delete:', data); + }; + + const handleUpdate = (data: any) => { + // console.log('Update:', data); + }; + + const handleTrashDelete = (data: any) => { + // console.log('Trash Delete:', data); + }; + + const handleDuplicate = async (data: any) => { + console.log("Project duplicate response:", data); + if (data?.message === "Project Duplicated successfully") { + if (setWorkspaceProjects) { + const allProjects = await getAllProjects(userId, organization); + console.log('allProjects: ', allProjects); + setWorkspaceProjects(allProjects); + } else if (setRecentProjects) { + const recentProjects = await recentlyViewed(organization, userId); + setRecentProjects && setRecentProjects(recentProjects); + } + setIsSearchActive && setIsSearchActive(false); + } else { + console.warn("Duplication failed or unexpected response."); + } + }; + + projectSocket.on("v1-project:response:add", handleAdd); + projectSocket.on("v1-project:response:delete", handleDelete); + projectSocket.on("v1-project:response:update", handleUpdate); + projectSocket.on("v1-project:response:Duplicate", handleDuplicate); + projectSocket.on("v1:trash:response:delete", handleTrashDelete); + + return () => { + projectSocket.off("v1-project:response:add", handleAdd); + projectSocket.off("v1-project:response:delete", handleDelete); + projectSocket.off("v1-project:response:update", handleUpdate); + projectSocket.off("v1-project:response:Duplicate", handleDuplicate); + projectSocket.off("v1:trash:response:delete", handleTrashDelete); + }; + }, [projectSocket, userId, organization]); + + return null; +}; + +export default ProjectSocketRes; -- 2.40.1 From 0d98892dffa3949932f1fa1c7c99446aca75a553 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 4 Jun 2025 11:55:59 +0530 Subject: [PATCH 16/21] updated api and socket for builder and visualization --- app/package-lock.json | 1 + app/src/components/Dashboard/SidePannel.tsx | 9 +- .../properties/GlobalProperties.tsx | 22 +- .../properties/ZoneProperties.tsx | 8 +- .../IotInputCards/BarChartInput.tsx | 25 +- .../FleetEfficiencyInputComponent.tsx | 4 +- .../IotInputCards/FlotingWidgetInput.tsx | 4 +- .../IotInputCards/LineGrapInput.tsx | 24 +- .../IotInputCards/PieChartInput.tsx | 25 +- .../IotInputCards/Progress1Input.tsx | 25 +- .../IotInputCards/Progress2Input.tsx | 25 +- .../WarehouseThroughputInputComponent.tsx | 4 +- .../IotInputCards/Widget2InputCard3D.tsx | 4 +- .../IotInputCards/Widget3InputCard3D.tsx | 4 +- .../IotInputCards/Widget4InputCard3D.tsx | 4 +- app/src/components/ui/Tools.tsx | 3 + app/src/components/ui/list/DropDownList.tsx | 4 +- app/src/components/ui/list/List.tsx | 26 +- .../IntialLoad/loadInitialFloorItems.ts | 7 +- .../IntialLoad/loadInitialWallItems.ts | 3 +- .../builder/assetGroup/assetsGroup.tsx | 7 +- app/src/modules/builder/builder.tsx | 4 +- app/src/modules/builder/dfx/LoadBlueprint.tsx | 6 +- .../dragControlDeclaration.ts | 7 +- .../geomentries/assets/addAssetModel.ts | 25 +- .../geomentries/assets/deleteFloorItems.ts | 10 +- .../geomentries/floors/drawOnlyFloor.ts | 12 +- .../builder/geomentries/layers/deleteLayer.ts | 7 +- .../builder/geomentries/lines/deleteLine.ts | 7 +- .../lines/distanceText/distanceText.tsx | 4 +- .../builder/geomentries/lines/drawWall.ts | 15 +- .../builder/geomentries/lines/splitLine.ts | 8 +- .../builder/geomentries/points/deletePoint.ts | 7 +- .../builder/geomentries/walls/addWallItems.ts | 7 +- .../geomentries/walls/deleteWallItems.ts | 6 +- .../builder/groups/floorGroupAisle.tsx | 563 +++++++++++------- .../builder/groups/floorItemsGroup.tsx | 18 +- .../modules/builder/groups/floorPlanGroup.tsx | 18 +- .../modules/builder/groups/wallItemsGroup.tsx | 14 +- app/src/modules/builder/groups/wallsMesh.tsx | 4 +- app/src/modules/builder/groups/zoneGroup.tsx | 94 ++- .../collaboration/camera/collabCams.tsx | 4 +- .../socket/socketResponses.dev.tsx | 52 +- app/src/modules/scene/camera/switchView.tsx | 4 +- .../scene/camera/updateCameraPosition.ts | 5 +- app/src/modules/scene/controls/controls.tsx | 11 +- .../selectionControls/copyPasteControls.tsx | 11 +- .../selectionControls/duplicationControls.tsx | 10 +- .../selectionControls/moveControls.tsx | 6 +- .../selectionControls/rotateControls.tsx | 6 +- .../selectionControls/selectionControls.tsx | 6 +- .../transformControls/transformControls.tsx | 8 +- .../visualization/RealTimeVisulization.tsx | 21 +- .../functions/handleSaveTemplate.ts | 7 +- .../visualization/functions/handleUiDrop.ts | 27 +- .../socket/realTimeVizSocket.dev.tsx | 49 +- .../visualization/template/Templates.tsx | 17 +- .../widgets/2d/DraggableWidget.tsx | 20 +- .../widgets/2d/charts/BarGraphComponent.tsx | 15 +- .../2d/charts/DoughnutGraphComponent.tsx | 17 +- .../widgets/2d/charts/LineGraphComponent.tsx | 15 +- .../widgets/2d/charts/PieGraphComponent.tsx | 14 +- .../2d/charts/PolarAreaGraphComponent.tsx | 14 +- .../widgets/2d/charts/ProgressCard1.tsx | 14 +- .../widgets/2d/charts/ProgressCard2.tsx | 14 +- .../widgets/3d/Dropped3dWidget.tsx | 152 ++--- .../floating/DroppedFloatingWidgets.tsx | 14 +- .../widgets/floating/cards/SimpleCard.tsx | 2 +- .../widgets/panel/AddButtons.tsx | 88 +-- .../visualization/widgets/panel/Panel.tsx | 41 +- .../visualization/zone/DisplayZone.tsx | 46 +- app/src/pages/Dashboard.tsx | 3 - app/src/pages/Project.tsx | 8 +- app/src/services/dashboard/createProject.ts | 4 +- .../assest/floorAsset/getFloorItemsApi.ts | 8 +- .../assest/floorAsset/setFloorItemApi.ts | 5 +- .../assest/wallAsset/getWallItemsApi.ts | 9 +- .../factoryBuilder/camera/getCameraApi.ts | 15 +- .../environment/findEnvironment.ts | 12 +- .../environment/setEnvironment.ts | 19 +- .../factoryBuilder/lines/getLinesApi.ts | 8 +- .../factoryBuilder/zones/deleteZoneApi.ts | 4 +- .../factoryBuilder/zones/getZonesApi.ts | 14 +- .../services/visulization/zone/add3dWidget.ts | 9 +- .../visulization/zone/addFloatingWidgets.ts | 9 +- .../services/visulization/zone/addWidgets.ts | 10 +- .../services/visulization/zone/clearPanel.ts | 9 +- .../visulization/zone/delete3dWidget.ts | 9 +- .../visulization/zone/deleteFloatingWidget.ts | 5 +- .../services/visulization/zone/deletePanel.ts | 9 +- .../visulization/zone/deleteTemplate.ts | 5 +- .../visulization/zone/deleteWidgetApi.ts | 9 +- .../visulization/zone/duplicateWidget.ts | 9 +- .../visulization/zone/get3dWidgetData.ts | 12 +- .../visulization/zone/getFloatingData.ts | 10 +- .../visulization/zone/getSelect2dZoneData.ts | 10 +- .../services/visulization/zone/getTemplate.ts | 7 +- .../services/visulization/zone/getZoneData.ts | 8 +- .../services/visulization/zone/getZones.ts | 7 +- .../visulization/zone/loadTemplate.ts | 9 +- .../services/visulization/zone/lockPanel.ts | 4 +- app/src/services/visulization/zone/panel.ts | 9 +- .../visulization/zone/saveTempleteApi.ts | 5 +- .../visulization/zone/update3dWidget.ts | 26 +- .../visulization/zone/zoneCameraUpdation.ts | 7 +- app/src/store/builder/store.ts | 9 +- .../visualization/useDroppedObjectsStore.ts | 23 +- .../visualization/useZone3DWidgetStore.ts | 42 +- app/src/store/visualization/useZoneStore.ts | 6 +- 109 files changed, 1382 insertions(+), 788 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index a752e9c..fff13e1 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -10133,6 +10133,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/dxf-parser/-/dxf-parser-1.1.2.tgz", "integrity": "sha512-GPTumUvRkounlIazLIyJMmTWt+nlg+ksS0Hdm8jWvejmZKBTz6gvHTam76wRm4PQMma5sgKLThblQyeIJcH79Q==", + "license": "MIT", "dependencies": { "loglevel": "^1.7.1" } diff --git a/app/src/components/Dashboard/SidePannel.tsx b/app/src/components/Dashboard/SidePannel.tsx index 4bb7f61..03392f4 100644 --- a/app/src/components/Dashboard/SidePannel.tsx +++ b/app/src/components/Dashboard/SidePannel.tsx @@ -39,9 +39,8 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { try { const projectId = generateProjectId(); useSocketStore.getState().initializeSocket(email, organization, token); - console.log('projectId: ', projectId); - navigate(`/${projectId}`); - setLoadingProgress(1) + + //API for creating new Project // const project = await createProject( // projectId, @@ -63,6 +62,10 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { // 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}`); + } projectSocket.off("v1-project:response:add", handleResponse); // Clean up }; projectSocket.on("v1-project:response:add", handleResponse); diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 0422e2b..191bb15 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -20,6 +20,7 @@ import { import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment"; import * as CONSTANTS from "../../../../types/world/worldConstants"; import { validateBBox } from "@turf/helpers"; +import { useParams } from "react-router-dom"; const GlobalProperties: React.FC = () => { const { toggleView, setToggleView } = useToggleView(); const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); @@ -37,6 +38,7 @@ const GlobalProperties: React.FC = () => { const [limitGridDistance, setLimitGridDistance] = useState(false); const [gridDistance, setGridDistance] = useState(3); + const { projectId } = useParams(); const optimizeScene = async (value: any) => { const email = localStorage.getItem("email"); @@ -49,7 +51,8 @@ const GlobalProperties: React.FC = () => { roofVisibility, shadows, 30, - true + true, + projectId ); setRenderDistance(30); setLimitDistance(true); @@ -67,7 +70,8 @@ const GlobalProperties: React.FC = () => { roofVisibility, shadows, 75, - !limitDistance + !limitDistance, + projectId ); setRenderDistance(75); } else { @@ -78,7 +82,8 @@ const GlobalProperties: React.FC = () => { roofVisibility, shadows, renderDistance, - !limitDistance + !limitDistance, + projectId ); } setLimitDistance(!limitDistance); @@ -111,7 +116,8 @@ const GlobalProperties: React.FC = () => { roofVisibility, shadows, value, - limitDistance + limitDistance, + projectId ); }; @@ -128,7 +134,8 @@ const GlobalProperties: React.FC = () => { !roofVisibility, shadows, renderDistance, - limitDistance + limitDistance, + projectId ); // @@ -157,7 +164,7 @@ const GlobalProperties: React.FC = () => { roofVisibility, shadows, renderDistance, - limitDistance + limitDistance,projectId ); // @@ -186,7 +193,8 @@ const GlobalProperties: React.FC = () => { roofVisibility, !shadows, renderDistance, - limitDistance + limitDistance, + projectId ); // diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index e116c15..35f3bb5 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -28,7 +28,7 @@ const ZoneProperties: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; let zonesdata = { - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, viewPortposition: zonePosition, viewPortCenter: zoneTarget, }; @@ -52,7 +52,7 @@ const ZoneProperties: React.FC = () => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const zonesdata = { - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, zoneName: newName, }; // Call your API to update the zone @@ -61,7 +61,7 @@ const ZoneProperties: React.FC = () => { if (response.message === "updated successfully") { setZones((prevZones: any[]) => prevZones.map((zone) => - zone.zoneId === selectedZone.zoneId + zone.zoneUuid === selectedZone.zoneUuid ? { ...zone, zoneName: newName } : zone ) @@ -80,7 +80,7 @@ const ZoneProperties: React.FC = () => { return zones.some( (zone: any) => zone.zoneName.trim().toLowerCase() === name.trim().toLowerCase() && - zone.zoneId !== selectedZone.zoneId + zone.zoneUuid !== selectedZone.zoneUuid ); }; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx index 742569c..27ac2f9 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx @@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import { useParams } from "react-router-dom"; type Props = {}; @@ -24,6 +25,8 @@ const BarChartInput = (props: Props) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const [isLoading, setLoading] = useState(true); + const { projectId } = useParams(); + useEffect(() => { const fetchZoneData = async () => { @@ -50,7 +53,15 @@ const BarChartInput = (props: Props) => { if (selectedChartId.id !== "") { try { const response = await axios.get( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}` + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } ); if (response.status === 200) { setSelections(response.data.Data.measurements); @@ -83,10 +94,18 @@ const BarChartInput = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, panel: selectedChartId.panel, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx index 6b3559c..4d858ff 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx @@ -87,10 +87,10 @@ const FleetEfficiencyInputComponent = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, header: inputName, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx index 166070e..9fc36b9 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx @@ -86,10 +86,10 @@ const FlotingWidgetInput = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, header: inputName, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index 49d4525..330560f 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -123,6 +123,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import { useParams } from "react-router-dom"; type Props = {}; @@ -140,6 +141,7 @@ const LineGrapInput = (props: Props) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const [isLoading, setLoading] = useState(true); + const { projectId } = useParams(); useEffect(() => { const fetchZoneData = async () => { @@ -166,7 +168,15 @@ const LineGrapInput = (props: Props) => { if (selectedChartId.id !== "") { try { const response = await axios.get( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}` + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } ); if (response.status === 200) { setSelections(response.data.Data.measurements); @@ -199,10 +209,18 @@ const LineGrapInput = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, panel: selectedChartId.panel, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx index aa0acaa..a78e391 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import { useParams } from "react-router-dom"; type Props = {}; @@ -24,6 +25,8 @@ const PieChartInput = (props: Props) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const [isLoading, setLoading] = useState(true); + const { projectId } = useParams(); + useEffect(() => { const fetchZoneData = async () => { @@ -50,7 +53,15 @@ const PieChartInput = (props: Props) => { if (selectedChartId.id !== "") { try { const response = await axios.get( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}` + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } ); if (response.status === 200) { setSelections(response.data.Data.measurements); @@ -83,10 +94,18 @@ const PieChartInput = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, panel: selectedChartId.panel, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx index 2f1fdb5..15ecee5 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx @@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import { useParams } from "react-router-dom"; type Props = {}; @@ -24,6 +25,8 @@ const Progress1Input = (props: Props) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const [isLoading, setLoading] = useState(true); + const { projectId } = useParams(); + useEffect(() => { const fetchZoneData = async () => { @@ -50,7 +53,15 @@ const Progress1Input = (props: Props) => { if (selectedChartId.id !== "") { try { const response = await axios.get( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}` + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } ); if (response.status === 200) { setSelections(response.data.Data.measurements); @@ -83,10 +94,18 @@ const Progress1Input = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, panel: selectedChartId.panel, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx index 2d2e089..842821c 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx @@ -7,6 +7,7 @@ import { useSelectedZoneStore } from "../../../../../store/visualization/useZone import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import { useParams } from "react-router-dom"; type Props = {}; @@ -24,6 +25,8 @@ const Progress2Input = (props: Props) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const [isLoading, setLoading] = useState(true); + const { projectId } = useParams(); + useEffect(() => { const fetchZoneData = async () => { @@ -50,7 +53,15 @@ const Progress2Input = (props: Props) => { if (selectedChartId.id !== "") { try { const response = await axios.get( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}` + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/data?widgetID=${selectedChartId.id}&zoneUuid=${selectedZone.zoneUuid}&projectId=${projectId}`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + } ); if (response.status === 200) { setSelections(response.data.Data.measurements); @@ -83,10 +94,18 @@ const Progress2Input = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget/save`, + { + headers: { + Authorization: "Bearer ", // Replace with actual token + "Content-Type": "application/json", + token: localStorage.getItem("token") || "", // Coerce null to empty string + refresh_token: localStorage.getItem("refreshToken") || "", + }, + }, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, panel: selectedChartId.panel, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx index 6c8eda4..b963c8c 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx @@ -84,10 +84,10 @@ const WarehouseThroughputInputComponent = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/floatWidget/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, header: inputName, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx index 0723c80..10c905c 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx @@ -83,10 +83,10 @@ const Widget2InputCard3D = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, widgetName: inputName, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx index 2e2b051..d9e4314 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx @@ -80,10 +80,10 @@ const Widget3InputCard3D = () => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, widgetName: inputName, diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx index cc8d9ca..2498d3d 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx @@ -83,10 +83,10 @@ const Widget4InputCard3D = (props: Props) => { ) => { try { const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, { organization: organization, - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, widget: { id: selectedChartId.id, widgetName: inputName, diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index fcc40b8..b36b00f 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -37,6 +37,7 @@ import { use3DWidget, useFloatingWidget, } from "../../store/visualization/useDroppedObjectsStore"; +import { useParams } from "react-router-dom"; // Utility component const ToolButton = ({ @@ -89,6 +90,7 @@ const Tools: React.FC = () => { const dropdownRef = useRef(null); const [openDrop, setOpenDrop] = useState(false); + const { projectId } = useParams(); // 1. Set UI toggles on initial render useEffect(() => { @@ -257,6 +259,7 @@ const Tools: React.FC = () => { selectedZone, templates, visualizationSocket, + projectId }) } /> diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 77c9c4b..8c76aba 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -17,7 +17,7 @@ interface DropDownListProps { } interface Zone { - zoneId: string; + zoneUuid: string; zoneName: string; points: [number, number, number][]; // polygon vertices } @@ -93,7 +93,7 @@ const DropDownList: React.FC = ({ })); return { - id: zone.zoneId, + id: zone.zoneUuid, name: zone.zoneName, assets: assetsInZone, }; diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index d5db7fb..dd610d6 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -20,6 +20,7 @@ import { import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation"; import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import OuterClick from "../../../utils/outerClick"; +import { useParams } from "react-router-dom"; interface Asset { id: string; @@ -50,6 +51,7 @@ const List: React.FC = ({ items = [], remove }) => { {} ); const { setFloorItems } = useFloorItems(); + const { projectId } = useParams(); useEffect(() => { @@ -58,23 +60,23 @@ const List: React.FC = ({ items = [], remove }) => { activeSides: [], panelOrder: [], lockedPanels: [], - zoneId: "", + zoneUuid: "", zoneViewPortTarget: [], zoneViewPortPosition: [], widgets: [], }); }, [activeModule]); - const toggleZoneExpansion = (zoneId: string) => { + const toggleZoneExpansion = (zoneUuid: string) => { setExpandedZones((prev) => ({ ...prev, - [zoneId]: !prev[zoneId], + [zoneUuid]: !prev[zoneUuid], })); }; async function handleSelectZone(id: string) { try { - if (selectedZone?.zoneId === id) { + if (selectedZone?.zoneUuid === id) { return; } @@ -83,14 +85,14 @@ const List: React.FC = ({ items = [], remove }) => { const email = localStorage.getItem("email"); const organization = email?.split("@")[1]?.split(".")[0] ?? ""; - let response = await getZoneData(id, organization); + let response = await getZoneData(id, organization, projectId); setSelectedZone({ zoneName: response?.zoneName, activeSides: response?.activeSides ?? [], panelOrder: response?.panelOrder ?? [], lockedPanels: response?.lockedPanels ?? [], widgets: response?.widgets ?? [], - zoneId: response?.zoneId, + zoneUuid: response?.zoneUuid, zoneViewPortTarget: response?.viewPortCenter ?? [], zoneViewPortPosition: response?.viewPortposition ?? [], }); @@ -110,7 +112,7 @@ const List: React.FC = ({ items = [], remove }) => { const isDuplicate = zones.some( (zone: any) => zone.zoneName.trim().toLowerCase() === newName.trim().toLowerCase() && - zone.zoneId !== selectedZone.zoneId + zone.zoneUuid !== selectedZone.zoneUuid ); if (isDuplicate) { @@ -119,7 +121,7 @@ const List: React.FC = ({ items = [], remove }) => { } const zonesdata = { - zoneId: selectedZone.zoneId, + zoneUuid: selectedZone.zoneUuid, zoneName: newName, }; @@ -129,7 +131,7 @@ const List: React.FC = ({ items = [], remove }) => { setZones((prevZones: any[]) => prevZones.map((zone) => - zone.zoneId === selectedZone.zoneId + zone.zoneUuid === selectedZone.zoneUuid ? { ...zone, zoneName: newName } : zone ) @@ -161,7 +163,7 @@ const List: React.FC = ({ items = [], remove }) => { return zones.some( (zone: any) => zone.zoneName.trim().toLowerCase() === name.trim().toLowerCase() && - zone.zoneId !== selectedZone.zoneId + zone.zoneUuid !== selectedZone.zoneUuid ); }; @@ -199,7 +201,7 @@ const List: React.FC = ({ items = [], remove }) => { if (isOutsideClick(evt.target)) { // Clear selected zone setSelectedZone({ - zoneId: '', + zoneUuid: '', zoneName: '', activeSides: [], panelOrder: [], @@ -241,7 +243,7 @@ const List: React.FC = ({ items = [], remove }) => { toggleZoneExpansion(item.id); }} > -
+