From 3ab5c6ee6a1b80d9c5bb4cfecc6892c46c5982d2 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 25 Jun 2025 11:11:23 +0530 Subject: [PATCH 1/7] Refactor 3D Widget Input Handling and Cleanup - Removed commented-out code related to adding 3D widgets from BarChartInput, LineGrapInput, PieChartInput, Progress1Input, Progress2Input components. - Updated widget input fetching logic in Widget2InputCard3D, Widget3InputCard3D, and Widget4InputCard3D to include projectId and versionId. - Enhanced error handling and logging in add3dWidget and get3dWidgetInput services. - Cleaned up console logs and unnecessary comments across various components for better readability. - Ensured consistent handling of widget data structure in ProductionCapacity, ReturnOfInvestment, StateWorking, and Throughput components. --- .../IotInputCards/BarChartInput.tsx | 11 +- .../IotInputCards/LineGrapInput.tsx | 10 +- .../IotInputCards/PieChartInput.tsx | 10 +- .../IotInputCards/Progress1Input.tsx | 10 +- .../IotInputCards/Progress2Input.tsx | 10 -- .../IotInputCards/Widget2InputCard3D.tsx | 113 +++++++++-------- .../IotInputCards/Widget3InputCard3D.tsx | 112 +++++++++-------- .../IotInputCards/Widget4InputCard3D.tsx | 116 ++++++++++-------- app/src/modules/builder/dfx/LoadBlueprint.tsx | 1 + .../geomentries/floors/drawOnlyFloor.ts | 2 + .../builder/geomentries/lines/drawWall.ts | 2 + .../builder/geomentries/lines/splitLine.ts | 2 + .../widgets/3d/Dropped3dWidget.tsx | 30 ++--- .../widgets/3d/cards/ProductionCapacity.tsx | 20 ++- .../widgets/3d/cards/ReturnOfInvestment.tsx | 16 ++- .../widgets/3d/cards/StateWorking.tsx | 24 ++-- .../widgets/3d/cards/Throughput.tsx | 24 ++-- .../services/visulization/zone/add3dWidget.ts | 13 +- .../visulization/zone/get3dWidgetInput.ts | 13 +- 19 files changed, 299 insertions(+), 240 deletions(-) diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx index 3b7e67a..09da02b 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx @@ -91,16 +91,7 @@ const BarChartInput = (props: Props) => { duration: inputDuration, } } - // const adding3dWidget = { - // organization: organization, - // widget: newWidget, - // zoneUuid: selectedZone.zoneUuid, - // projectId, userId - // }; - // if (visualizationSocket) { - // visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); - - // } + let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || ""); diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index 646ba88..29263fe 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -210,15 +210,7 @@ const LineGrapInput = (props: Props) => { } } - // const adding3dWidget = { - // organization: organization, - // widget: newWidget, - // zoneUuid: selectedZone.zoneUuid, - // projectId, userId - // }; - // if (visualizationSocket) { - // visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); - // } + let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || ""); if (response.message === "Widget updated successfully") { diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx index 04ac73b..26988aa 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -94,15 +94,7 @@ const PieChartInput = (props: Props) => { duration: inputDuration, }, } - // const adding3dWidget = { - // organization: organization, - // widget: newWidget, - // zoneUuid: selectedZone.zoneUuid, - // projectId, userId - // }; - // if (visualizationSocket) { - // visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); - // } + let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || ""); diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx index 1f573b3..6854848 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx @@ -93,15 +93,7 @@ const Progress1Input = (props: Props) => { duration: inputDuration, }, } - // const adding3dWidget = { - // organization: organization, - // widget: newWidget, - // zoneUuid: selectedZone.zoneUuid, - // projectId, userId - // }; - // if (visualizationSocket) { - // visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); - // } + let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || ""); if (response.message === "Widget updated successfully") { diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx index f1af380..2482346 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx @@ -94,16 +94,6 @@ const Progress2Input = (props: Props) => { } } - // const adding3dWidget = { - // organization: organization, - // widget: newWidget, - // zoneUuid: selectedZone.zoneUuid, - // projectId, userId - // }; - // if (visualizationSocket) { - // visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); - // } - let response = await addingWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || ""); if (response.message === "Widget updated successfully") { diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx index 79fd00e..0889809 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx @@ -38,15 +38,15 @@ const Widget2InputCard3D = (props: Props) => { setLoading(true); const response = await axios.get(`http://${iotApiUrl}/floatinput`); if (response.status === 200) { - // console.log("dropdown data:", response.data); + // setDropDownData(response.data); setLoading(false); } else { - // console.log("Unexpected response:", response); + // } } catch (error) { echo.error("Failed to fetch zone data"); - console.error("There was an error!", error); + } }; fetchZoneData(); @@ -55,14 +55,14 @@ const Widget2InputCard3D = (props: Props) => { useEffect(() => { const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { - let response = await get3dWidgetInput(selectedChartId.id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "") + if (response) { - setSelections(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setWidgetName(response.data.widgetName); + setSelections(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setWidgetName(response.widgetName); } - + } }; @@ -81,44 +81,61 @@ const Widget2InputCard3D = (props: Props) => { inputDuration: any, inputName: any ) => { - // let newWidget = { - // id: selectedChartId.id, - // widgetName: inputName, - // Data: { - // measurements: inputMeasurement, - // duration: inputDuration, - // }, - // } - - // let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget,projectId, selectedVersion?.versionId || "") - // console.log('response: ', response); - try { - const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, - { - organization, - zoneUuid: selectedZone.zoneUuid, - widget: { - id: selectedChartId.id, - widgetName: inputName, - Data: { - measurements: inputMeasurement, - duration: inputDuration, - }, - }, - } as any - ); - if (response.status === 200) { - return true; - } else { - // console.log("Unexpected response:", response); - return false; - } - } catch (error) { - echo.error("Failed to send input"); - console.error("There was an error!", error); - return false; + let newWidget = { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration, + }, } + + let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "") + + if (response.message === "widget update successfully") { + return true; + } else { + return false + } + // try { + // const response = await axios.post( + // `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, + // { + // headers: { + // Authorization: "Bearer ", + // "Content-Type": "application/json", + // token: localStorage.getItem("token") || "", + // refresh_token: localStorage.getItem("refreshToken") || "", + // }, + // }, + // { + // organization, + // zoneUuid: selectedZone.zoneUuid, + // widget: { + // id: selectedChartId.id, + // widgetName: inputName, + // Data: { + // measurements: inputMeasurement, + // duration: inputDuration, + // }, + // }, + // projectId: projectId, + // versionId: selectedVersion?.versionId || "" + // } as any, + + // ); + // + // if (response.status === 200) { + // return true; + // } else { + // // + // return false; + // } + // } catch (error) { + // echo.error("Failed to send input"); + // + // return false; + // } }; const handleSelect = async ( @@ -133,7 +150,7 @@ const Widget2InputCard3D = (props: Props) => { newSelections[inputKey] = selectedData; } // setMeasurements(newSelections); // Update Zustand store - // console.log(newSelections); + // if (await sendInputes(newSelections, duration, widgetName)) { setSelections(newSelections); } @@ -150,7 +167,7 @@ const Widget2InputCard3D = (props: Props) => { }; const handleNameChange = async (name: any) => { - // console.log("name change requested", name); + // if (await sendInputes(selections, duration, name)) { setWidgetName(name); diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx index 3e0ddde..a236d5a 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx @@ -36,15 +36,15 @@ const Widget3InputCard3D = () => { setLoading(true); const response = await axios.get(`http://${iotApiUrl}/getinput`); if (response.status === 200) { - // console.log("dropdown data:", response.data); + // setDropDownData(response.data); setLoading(false); } else { - // console.log("Unexpected response:", response); + // } } catch (error) { echo.error("Failed to fetch zone data"); - console.error("There was an error!", error); + } }; fetchZoneData(); @@ -53,12 +53,12 @@ const Widget3InputCard3D = () => { useEffect(() => { const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { - let response = await get3dWidgetInput(selectedChartId.id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "") + if (response) { - setSelections(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setWidgetName(response.data.widgetName); + setSelections(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setWidgetName(response.widgetName); } } @@ -79,45 +79,61 @@ const Widget3InputCard3D = () => { inputName: any ) => { - // let newWidget = { - // id: selectedChartId.id, - // widgetName: inputName, - // Data: { - // measurements: inputMeasurement, - // duration: inputDuration, - // }, - // } - - // let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "") - // console.log('response: ', response); - - try { - const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, - { - organization, - zoneUuid: selectedZone.zoneUuid, - widget: { - id: selectedChartId.id, - widgetName: inputName, - Data: { - measurements: inputMeasurement, - duration: inputDuration, - }, - }, - } as any - ); - if (response.status === 200) { - return true; - } else { - // console.log("Unexpected response:", response); - return false; - } - } catch (error) { - echo.error("Failed to send input"); - console.error("There was an error!", error); - return false; + let newWidget = { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration, + }, } + + let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "") + + if (response.message === "widget update successfully") { + return true; + } else { + return false + } + + // try { + // const response = await axios.post( + // `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, + // { + // headers: { + // Authorization: "Bearer ", + // "Content-Type": "application/json", + // token: localStorage.getItem("token") || "", + // refresh_token: localStorage.getItem("refreshToken") || "", + // }, + // }, + // { + // organization, + // zoneUuid: selectedZone.zoneUuid, + // widget: { + // id: selectedChartId.id, + // widgetName: inputName, + // Data: { + // measurements: inputMeasurement, + // duration: inputDuration, + // }, + // }, + // projectId: projectId, + // versionId: selectedVersion?.versionId || "" + // } as any + // ); + // + // if (response.status === 200) { + // return true; + // } else { + // // + // return false; + // } + // } catch (error) { + // echo.error("Failed to send input"); + // + // return false; + // } }; const handleSelect = async ( @@ -132,7 +148,7 @@ const Widget3InputCard3D = () => { newSelections[inputKey] = selectedData; } // setMeasurements(newSelections); // Update Zustand store - // console.log(newSelections); + // if (await sendInputes(newSelections, duration, widgetName)) { setSelections(newSelections); } @@ -145,7 +161,7 @@ const Widget3InputCard3D = () => { }; const handleNameChange = async (name: any) => { - // console.log("name change requested", name); + // if (await sendInputes(selections, duration, name)) { setWidgetName(name); diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx index 2da2e61..df09e7b 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx @@ -38,15 +38,15 @@ const Widget4InputCard3D = (props: Props) => { setLoading(true); const response = await axios.get(`http://${iotApiUrl}/floatinput`); if (response.status === 200) { - // console.log("dropdown data:", response.data); + // setDropDownData(response.data); setLoading(false); } else { - // console.log("Unexpected response:", response); + // } } catch (error) { echo.error("Failed to fetch zone data"); - console.error("There was an error!", error); + } }; fetchZoneData(); @@ -55,14 +55,17 @@ const Widget4InputCard3D = (props: Props) => { useEffect(() => { const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { - let response = await get3dWidgetInput(selectedChartId.id, organization) - console.log('response: ', response); + + + + let response = await get3dWidgetInput(selectedChartId.id, organization, projectId, selectedVersion?.versionId || "") + if (response) { - setSelections(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setWidgetName(response.data.widgetName); + setSelections(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setWidgetName(response.widgetName); } - + } }; @@ -81,44 +84,61 @@ const Widget4InputCard3D = (props: Props) => { inputDuration: any, inputName: any ) => { - // let newWidget = { - // id: selectedChartId.id, - // widgetName: inputName, - // Data: { - // measurements: inputMeasurement, - // duration: inputDuration, - // }, - // } - - // let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "") - // console.log('response: ', response); - try { - const response = await axios.post( - `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, - { - organization, - zoneUuid: selectedZone.zoneUuid, - widget: { - id: selectedChartId.id, - widgetName: inputName, - Data: { - measurements: inputMeasurement, - duration: inputDuration, - }, - }, - } as any - ); - if (response.status === 200) { - return true; - } else { - // console.log("Unexpected response:", response); - return false; - } - } catch (error) { - echo.error("Failed to send input"); - console.error("There was an error!", error); - return false; + let newWidget = { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration, + }, } + + let response = await adding3dWidgets(selectedZone.zoneUuid, organization, newWidget, projectId, selectedVersion?.versionId || "") + + if (response.message === "widget update successfully") { + return true; + } else { + return false + } + // + // try { + // const response = await axios.post( + // `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/V1/widget3d/save`, + // { + // headers: { + // Authorization: "Bearer ", + // "Content-Type": "application/json", + // token: localStorage.getItem("token") || "", + // refresh_token: localStorage.getItem("refreshToken") || "", + // }, + // }, + // { + // organization, + // zoneUuid: selectedZone.zoneUuid, + // widget: { + // id: selectedChartId.id, + // widgetName: inputName, + // Data: { + // measurements: inputMeasurement, + // duration: inputDuration, + // }, + // }, + // projectId: projectId, + // versionId: selectedVersion?.versionId || "" + // } as any + // ); + // + // if (response.status === 200) { + // return true; + // } else { + // // + // return false; + // } + // } catch (error) { + // echo.error("Failed to send input"); + // + // return false; + // } }; const handleSelect = async ( @@ -133,7 +153,7 @@ const Widget4InputCard3D = (props: Props) => { newSelections[inputKey] = selectedData; } // setMeasurements(newSelections); // Update Zustand store - // console.log(newSelections); + // if (await sendInputes(newSelections, duration, widgetName)) { setSelections(newSelections); } @@ -150,7 +170,7 @@ const Widget4InputCard3D = (props: Props) => { }; const handleNameChange = async (name: any) => { - console.log("name change requested", name); + if (await sendInputes(selections, duration, name)) { setWidgetName(name); diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx index 4c48d59..4e2425d 100644 --- a/app/src/modules/builder/dfx/LoadBlueprint.tsx +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -79,6 +79,7 @@ const DxfFile = ({ userId } + console.log('input: ', input); socket.emit('v1:Line:create', input); }) diff --git a/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts b/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts index ad837fe..74b06ef 100644 --- a/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts +++ b/app/src/modules/builder/geomentries/floors/drawOnlyFloor.ts @@ -158,6 +158,7 @@ async function drawOnlyFloor( userId, }; + console.log('input: ', input); socket.emit("v1:Line:create", input); setNewLines([newLines[0], newLines[1], line.current]); @@ -248,6 +249,7 @@ async function drawOnlyFloor( userId, }; + console.log('input: ', input); socket.emit("v1:Line:create", input); setNewLines([line.current]); diff --git a/app/src/modules/builder/geomentries/lines/drawWall.ts b/app/src/modules/builder/geomentries/lines/drawWall.ts index b64ed64..fb6cf10 100644 --- a/app/src/modules/builder/geomentries/lines/drawWall.ts +++ b/app/src/modules/builder/geomentries/lines/drawWall.ts @@ -141,6 +141,7 @@ async function drawWall( userId, }; + console.log('input: ', input); socket.emit("v1:Line:create", input); setNewLines([newLines[0], newLines[1], line.current]); @@ -222,6 +223,7 @@ async function drawWall( userId, }; + console.log('input: ', input); socket.emit("v1:Line:create", input); setNewLines([line.current]); diff --git a/app/src/modules/builder/geomentries/lines/splitLine.ts b/app/src/modules/builder/geomentries/lines/splitLine.ts index 2e8f9b1..31c2646 100644 --- a/app/src/modules/builder/geomentries/lines/splitLine.ts +++ b/app/src/modules/builder/geomentries/lines/splitLine.ts @@ -107,6 +107,7 @@ function splitLine( userId, }; + console.log('input1: ', input1); socket.emit("v1:Line:create", input1); //REST @@ -126,6 +127,7 @@ function splitLine( userId, }; + console.log('input2: ', input2); socket.emit("v1:Line:create", input2); lines.current.push(newLine1, newLine2); diff --git a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx index a9b65ea..ad00c35 100644 --- a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx +++ b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx @@ -106,17 +106,17 @@ export default function Dropped3dWidgets() { const hasEntered = { current: false }; const handleDragEnter = (event: DragEvent) => { - console.log("dragEnter"); + event.preventDefault(); event.stopPropagation(); if (hasEntered.current || !widgetSelect.startsWith("ui")) return; - console.log('hasEntered.current : ', hasEntered.current ); + hasEntered.current = true; - const group1 = scene.getObjectByName("itemsGroup"); - console.log('group1: ', group1); - if (!group1) return; + // const group1 = scene.getObjectByName("itemsGroup"); + // + // if (!group1) return; const rect = canvasElement.getBoundingClientRect(); mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; @@ -139,7 +139,7 @@ export default function Dropped3dWidgets() { intersect.object.type !== "GridHelper" ); - console.log('intersects: ', intersects); + if (intersects.length > 0) { const { x, y, z } = intersects[0].point; const newWidget: WidgetData = { @@ -238,10 +238,11 @@ export default function Dropped3dWidgets() { organization, widget: newWidget, zoneUuid: selectedZone.zoneUuid, - version: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || '', projectId, userId }; + if (visualizationSocket) { visualizationSocket.emit("v1:viz-3D-widget:add", add3dWidget); @@ -276,7 +277,7 @@ export default function Dropped3dWidgets() { const widgetToDuplicate = activeZoneWidgets.find( (w: WidgetData) => w.id === rightClickSelected ); - console.log("3d widget to duplecate", widgetToDuplicate); + if (!widgetToDuplicate) return; const newWidget: any = { @@ -301,6 +302,7 @@ export default function Dropped3dWidgets() { projectId, userId }; + if (visualizationSocket) { visualizationSocket.emit("v1:viz-3D-widget:add", adding3dWidget); } @@ -470,20 +472,20 @@ export default function Dropped3dWidgets() { } // if (rightSelect === "Vertical Move") { - // // console.log('rightSelect: ', rightSelect); + // // - // // console.log('floorPlanesVertical: ', floorPlanesVertical); - // // console.log('planeIntersect.current: ', planeIntersect.current); + // // + // // // // const intersect = raycaster.ray.intersectPlane( // // floorPlanesVertical, // // planeIntersect.current // // ); - // // console.log('intersect: ', intersect); + // // // let intersect = event.clientY // if (intersect && typeof intersectcontextmenu === "number") { - // console.log('intersect: ', intersect); + // // const diff = intersect - intersectcontextmenu; // const unclampedY = selectedWidget.position[1] + diff; // const newY = Math.max(0, unclampedY); // Prevent going below floor (y=0) @@ -495,7 +497,7 @@ export default function Dropped3dWidgets() { // newY, // selectedWidget.position[2], // ]; - // console.log('newPosition: ', newPosition); + // // updateWidgetPosition(selectedzoneUuid, rightClickSelected, newPosition); diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx index f951456..2a104c3 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx @@ -18,6 +18,8 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore"; import useChartStore from "../../../../../store/visualization/useChartStore"; import { getUserData } from "../../../../../functions/getUserData"; import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useParams } from "react-router-dom"; // Register ChartJS components ChartJS.register( @@ -70,6 +72,9 @@ const ProductionCapacity: React.FC = ({ }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const { userName, userId, organization, email } = getUserData(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams() // Chart data for a week const defaultChartData = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week @@ -171,12 +176,15 @@ const ProductionCapacity: React.FC = ({ const fetchSavedInputes = async () => { if (id !== "") { - let response = await get3dWidgetInput(id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "") + + if (response.message === "Widget not found") { + return + } if (response) { - setmeasurements(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setName(response.data.widgetName); + setmeasurements(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setName(response.widgetName); } // try { // const response = await axios.get( @@ -215,7 +223,7 @@ const ProductionCapacity: React.FC = ({ scale={scale} rotation={rotation} // class - wrapperClass="pointer-none" + // wrapperClass="pointer-none" // other transform zIndexRange={[1, 0]} diff --git a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx index 80cd269..514b278 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx @@ -19,6 +19,8 @@ import useChartStore from "../../../../../store/visualization/useChartStore"; import { WavyIcon } from "../../../../../components/icons/3dChartIcons"; import { getUserData } from "../../../../../functions/getUserData"; import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useParams } from "react-router-dom"; // Register Chart.js components ChartJS.register( @@ -79,6 +81,9 @@ const ReturnOfInvestment: React.FC = ({ datasets: [], }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams() const { userName, userId, organization, email } = getUserData(); // Improved sample data for the smooth curve graph (single day) const graphData: ChartData<"line"> = { @@ -200,8 +205,11 @@ const ReturnOfInvestment: React.FC = ({ const fetchSavedInputes = async () => { if (id !== "") { - let response = await get3dWidgetInput(id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "") + + if (response.message === "Widget not found") { + return + } if (response) { setmeasurements(response.data.Data.measurements); setDuration(response.data.Data.duration); @@ -216,11 +224,11 @@ const ReturnOfInvestment: React.FC = ({ // setDuration(response.data.Data.duration); // setName(response.data.widgetName); // } else { - // // console.log("Unexpected response:", response); + // // // } // } catch (error) { // echo.error("Failed to fetch saved inputs"); - // console.error("There was an error!", error); + // // } } }; diff --git a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx index f664661..e6e3b5f 100644 --- a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx @@ -7,6 +7,8 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore"; import useChartStore from "../../../../../store/visualization/useChartStore"; import { getUserData } from "../../../../../functions/getUserData"; import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useParams } from "react-router-dom"; // import image from "../../../../assets/image/temp/image.png"; interface StateWorkingProps { @@ -41,6 +43,9 @@ const StateWorking: React.FC = ({ const [datas, setDatas] = useState({}); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const { userName, userId, organization, email } = getUserData(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams() // const datas = [ // { key: "Oil Tank:", value: "24/341" }, // { key: "Oil Refin:", value: 36.023 }, @@ -78,12 +83,15 @@ const StateWorking: React.FC = ({ const fetchSavedInputes = async () => { if (id !== "") { - let response = await get3dWidgetInput(id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "") + + if (response.message === "Widget not found") { + return + } if (response) { - setmeasurements(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setName(response.data.widgetName); + setmeasurements(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setName(response.widgetName); } // try { // const response = await axios.get( @@ -94,17 +102,17 @@ const StateWorking: React.FC = ({ // setDuration(response.data.Data.duration); // setName(response.data.widgetName); // } else { - // // console.log("Unexpected response:", response); + // // // } // } catch (error) { // echo.error("Failed to fetch saved inputs"); - // console.error("There was an error!", error); + // // } } }; useEffect(() => { - fetchSavedInputes(); + // fetchSavedInputes(); }, []); useEffect(() => { diff --git a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx index ea87c7f..599b566 100644 --- a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx @@ -21,6 +21,8 @@ import useChartStore from "../../../../../store/visualization/useChartStore"; import { ThroughputIcon } from "../../../../../components/icons/3dChartIcons"; import { getUserData } from "../../../../../functions/getUserData"; import { get3dWidgetInput } from "../../../../../services/visulization/zone/get3dWidgetInput"; +import { useVersionContext } from "../../../../builder/version/versionContext"; +import { useParams } from "react-router-dom"; // Register Chart.js components ChartJS.register( @@ -83,6 +85,9 @@ const Throughput: React.FC = ({ }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const { userName, userId, organization, email } = getUserData(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { projectId } = useParams() @@ -180,12 +185,15 @@ const Throughput: React.FC = ({ const fetchSavedInputes = async () => { if (id !== "") { - let response = await get3dWidgetInput(id, organization) - console.log('response: ', response); + let response = await get3dWidgetInput(id, organization, projectId, selectedVersion?.versionId || "") + + if (response.message === "Widget not found") { + return + } if (response) { - setmeasurements(response.data.Data.measurements); - setDuration(response.data.Data.duration); - setName(response.data.widgetName); + setmeasurements(response.Datastructure.measurements); + setDuration(response.Datastructure.duration); + setName(response.widgetName); } // try { // const response = await axios.get( @@ -196,17 +204,17 @@ const Throughput: React.FC = ({ // setDuration(response.data.Data.duration); // setName(response.data.widgetName); // } else { - // // console.log("Unexpected response:", response); + // // // } // } catch (error) { // echo.error("Failed to fetch saved inputs"); - // console.error("There was an error!", error); + // // } } }; useEffect(() => { - fetchSavedInputes(); + // fetchSavedInputes(); }, []); useEffect(() => { diff --git a/app/src/services/visulization/zone/add3dWidget.ts b/app/src/services/visulization/zone/add3dWidget.ts index caca8d9..322c8bb 100644 --- a/app/src/services/visulization/zone/add3dWidget.ts +++ b/app/src/services/visulization/zone/add3dWidget.ts @@ -6,8 +6,10 @@ export const adding3dWidgets = async ( widget: {}, projectId?: string, versionId?: string - + ) => { + + try { const response = await fetch(`${url_Backend_dwinzo}/api/V1/widget3d/save`, { method: "POST", @@ -20,15 +22,16 @@ export const adding3dWidgets = async ( body: JSON.stringify({ organization, zoneUuid, widget, projectId, versionId }), }); + const newAccessToken = response.headers.get("x-access-token"); if (newAccessToken) { - //console.log("New token received:", newAccessToken); + // localStorage.setItem("token", newAccessToken); } if (!response.ok) { - console.error("Failed to add 3dwidget in the zone"); + } const result = await response.json(); @@ -36,9 +39,9 @@ export const adding3dWidgets = async ( } catch (error) { echo.error("Failed to add 3d widget"); if (error instanceof Error) { - console.log(error.message); + } else { - console.log("An unknown error occurred"); + } } }; diff --git a/app/src/services/visulization/zone/get3dWidgetInput.ts b/app/src/services/visulization/zone/get3dWidgetInput.ts index 71f38ef..25e817c 100644 --- a/app/src/services/visulization/zone/get3dWidgetInput.ts +++ b/app/src/services/visulization/zone/get3dWidgetInput.ts @@ -2,9 +2,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const get3dWidgetInput = async (chartId: string, organization: string, projectId?: string, versionId?: string) => { + + + + try { const response = await fetch( - `${url_Backend_dwinzo}/api/v2/widget3D/${chartId}/${organization}`, + `${url_Backend_dwinzo}/api/V1/widget3dData/${chartId}/${projectId}/${versionId}`, { method: "GET", headers: { @@ -15,9 +19,10 @@ export const get3dWidgetInput = async (chartId: string, organization: string, pr }, } ); + const newAccessToken = response.headers.get("x-access-token"); if (newAccessToken) { - //console.log("New token received:", newAccessToken); + // localStorage.setItem("token", newAccessToken); } @@ -25,10 +30,10 @@ export const get3dWidgetInput = async (chartId: string, organization: string, pr throw new Error("Failed to fetch zoneDatas"); } const result = await response.json(); - console.log('result: ', result); + return result; } catch (error: any) { echo.error("Failed to fetch 2d widget data"); - console.log(error.message); + } }; From 982c92cf26041bf1ff850186e7a107299f73e2eb Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 12:20:53 +0530 Subject: [PATCH 2/7] Add WallAsset, Floor, and Zone interfaces to builderTypes --- app/src/types/builderTypes.d.ts | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index 26dcf65..decde1d 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -10,6 +10,7 @@ interface Version { type VersionHistory = Version[]; + // Asset interface Asset { @@ -45,6 +46,22 @@ interface Asset { type Assets = Asset[]; +// Wall-Asset + +interface WallAsset { + modelUuid: string; + modelName: string; + assetId: string; + wallUuid: string; + position: [number, number, number]; + isLocked: boolean; + isVisible: boolean; + opacity: number; +} + +type WallAssets = WallAsset[]; + + // Point type PointTypes = 'Aisle' | 'Wall' | 'Floor' | 'Zone'; @@ -81,6 +98,35 @@ interface Wall { type Walls = Wall[]; +// Floor + +interface Floor { + floorUuid: string; + points: Point[]; + sideMaterial: string; + topMaterial: string; + floorDepth: number; + isBeveled: boolean; + bevelStrength: number; +} + +type Floors = Floor[]; + + +// Zone + +interface Zone { + zoneUuid: string; + zoneName: string; + zoneColor: string; + points: Point[]; + viewPortTarget: [number, number, number]; + viewPortPosition: [number, number, number]; +} + +type Zones = Zone[]; + + // Aisle type AisleTypes = 'solid-aisle' | 'dashed-aisle' | 'stripped-aisle' | 'dotted-aisle' | 'arrow-aisle' | 'arrows-aisle' | 'arc-aisle' | 'circle-aisle' | 'junction-aisle'; From 587ed6c9d7619c91d29b7bfee5b8fad3c7d21d41 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 15:26:53 +0530 Subject: [PATCH 3/7] Refactor builder store and remove wall store Refactor builder store and remove wall store - Consolidated wall-related state management into the builder store by removing the useWallStore. - Added new properties and setters for wall attributes (thickness, height, materials) in the builder store. - Introduced SelectedWallProperties and WallProperties components for managing wall properties in the sidebar. - Created a new floor store for managing floor-related state. - Added a wall asset store for managing wall assets. - Implemented a zone store for managing zones and their properties. - Updated sidebar styles for better layout and appearance. --- .../layout/sidebarRight/SideBarRight.tsx | 26 ++- .../properties/SelectedWallProperties.tsx | 143 ++++++++++++ .../{eventProperties => }/WallProperties.tsx | 78 ++----- app/src/modules/builder/builder.tsx | 2 +- .../modules/builder/groups/floorPlanGroup.tsx | 2 +- app/src/modules/builder/line/line.tsx | 10 +- .../point/helpers/usePointSnapping.tsx | 5 +- app/src/modules/builder/point/point.tsx | 9 +- .../builder/wall/Instances/instance/wall.tsx | 41 +++- .../builder/wall/Instances/wallInstances.tsx | 9 +- .../builder/wall/wallCreator/wallCreator.tsx | 5 +- app/src/modules/builder/wall/wallGroup.tsx | 14 ++ .../scene/postProcessing/postProcessing.tsx | 21 +- app/src/modules/scene/sceneContext.tsx | 24 +- app/src/store/builder/useBuilderStore.ts | 210 +++++++++-------- app/src/store/builder/useFloorStore.ts | 90 ++++++++ app/src/store/builder/useWallAssetStore.ts | 82 +++++++ app/src/store/builder/useWallStore.ts | 211 ++++++++++++++++++ app/src/store/builder/useWallStore.tsx | 200 ----------------- app/src/store/builder/useZoneStore.ts | 74 ++++++ app/src/styles/layout/sidebar.scss | 16 +- 21 files changed, 870 insertions(+), 402 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx rename app/src/components/layout/sidebarRight/properties/{eventProperties => }/WallProperties.tsx (67%) create mode 100644 app/src/store/builder/useFloorStore.ts create mode 100644 app/src/store/builder/useWallAssetStore.ts create mode 100644 app/src/store/builder/useWallStore.ts delete mode 100644 app/src/store/builder/useWallStore.tsx create mode 100644 app/src/store/builder/useZoneStore.ts diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index e7cc3db..d6413bc 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -23,12 +23,14 @@ import { useSelectedEventSphere, } from "../../../store/simulation/useSimulationStore"; import GlobalProperties from "./properties/GlobalProperties"; -import AsstePropertiies from "./properties/AssetProperties"; +import AssetProperties from "./properties/AssetProperties"; import ZoneProperties from "./properties/ZoneProperties"; import EventProperties from "./properties/eventProperties/EventProperties"; import VersionHistory from "./versionHisory/VersionHistory"; import AisleProperties from "./properties/AisleProperties"; -import WallProperties from "./properties/eventProperties/WallProperties"; +import WallProperties from "./properties/WallProperties"; +import { useBuilderStore } from "../../../store/builder/useBuilderStore"; +import SelectedWallProperties from "./properties/SelectedWallProperties"; const SideBarRight: React.FC = () => { const { activeModule } = useModuleStore(); @@ -36,6 +38,7 @@ const SideBarRight: React.FC = () => { const { toolMode } = useToolMode(); const { subModule, setSubModule } = useSubModuleStore(); const { selectedFloorItem } = useSelectedFloorItem(); + const { selectedWall } = useBuilderStore(); const { selectedEventData } = useSelectedEventData(); const { selectedEventSphere } = useSelectedEventSphere(); const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore(); @@ -143,7 +146,8 @@ const SideBarRight: React.FC = () => { {!viewVersionHistory && subModule === "properties" && activeModule !== "visualization" && - !selectedFloorItem && ( + !selectedFloorItem && + !selectedWall && (
{(() => { @@ -158,13 +162,26 @@ const SideBarRight: React.FC = () => {
)} + {!viewVersionHistory && subModule === "properties" && activeModule !== "visualization" && selectedFloorItem && (
- + +
+
+ )} + + {!viewVersionHistory && + subModule === "properties" && + activeModule !== "visualization" && + !selectedFloorItem && + selectedWall && ( +
+
+
)} @@ -178,6 +195,7 @@ const SideBarRight: React.FC = () => { )} + {/* simulation */} {!isVersionSaved && !viewVersionHistory && diff --git a/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx new file mode 100644 index 0000000..b647145 --- /dev/null +++ b/app/src/components/layout/sidebarRight/properties/SelectedWallProperties.tsx @@ -0,0 +1,143 @@ +import { useState } from "react"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; + +import defaultTexture from '../../../../assets/textures/floor/wall-tex.png'; +import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; +import { useSceneContext } from "../../../../modules/scene/sceneContext"; + +const SelectedWallProperties = () => { + const { selectedWall } = useBuilderStore(); + const { wallStore } = useSceneContext(); + const { getWallById, updateWall } = wallStore(); + + const [activeSide, setActiveSide] = useState<"side1" | "side2">("side1"); + + const materials = [ + { texture: defaultTexture, textureId: "Default Material", textureName: "Default Material" }, + { texture: wallTexture1, textureId: "Material 1", textureName: "Grunge Concrete Wall" } + ]; + + const wall = selectedWall ? getWallById(selectedWall.userData.wallUuid) : null; + + const handleHeightChange = (val: string) => { + const height = parseFloat(val); + if (!isNaN(height) && wall) { + updateWall(wall.wallUuid, { wallHeight: height }); + } + }; + + const handleThicknessChange = (val: string) => { + const thickness = parseFloat(val); + if (!isNaN(thickness) && wall) { + updateWall(wall.wallUuid, { wallThickness: thickness }); + } + }; + + const handleSelectMaterial = (material: { textureId: string; textureName: string }) => { + if (!wall) return; + + const updated = (activeSide === "side1" ? { insideMaterial: material.textureId } : { outsideMaterial: material.textureId }) + + updateWall(wall.wallUuid, updated); + }; + + if (!wall) return null; + + const selectedMaterials = { + side1: { + texture: materials.find((material) => material.textureId === wall.insideMaterial)?.texture || 'Unknown', + textureId: materials.find((material) => material.textureId === wall.insideMaterial)?.textureId || 'Unknown', + textureName: materials.find((material) => material.textureId === wall.insideMaterial)?.textureName || 'Unknown' + }, + side2: { + texture: materials.find((material) => material.textureId === wall.outsideMaterial)?.texture || 'Unknown', + textureId: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureId || 'Unknown', + textureName: materials.find((material) => material.textureId === wall.outsideMaterial)?.textureName || 'Unknown' + } + }; + + return ( +
+
+
Wall
+
+ + +
+
+
+
+
Materials
+
+ +
+
+ {(["side1", "side2"] as const).map((side) => ( + + ))} +
+ +
+ {selectedMaterials[activeSide].textureName} +
+
+ +
+
+ {materials.map((material, index) => { + const isSelected = selectedMaterials[activeSide].textureId === material.textureId; + + return ( + + ); + })} +
+
+
+
+ ); +}; + +export default SelectedWallProperties; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx similarity index 67% rename from app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx rename to app/src/components/layout/sidebarRight/properties/WallProperties.tsx index f3cb792..eb835f1 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/WallProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/WallProperties.tsx @@ -1,11 +1,12 @@ import { useEffect, useState } from "react"; -import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown"; -import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; // Texture Imports -import wallTexture1 from "../../../../../assets/image/wallTextures/wallTexture.png"; -import defaultTexture from "../../../../../assets/image/wallTextures/defaultTexture.jpg"; -import { useBuilderStore } from "../../../../../store/builder/useBuilderStore"; + +import defaultTexture from '../../../../assets/textures/floor/wall-tex.png'; +import wallTexture1 from '../../../../assets/textures/floor/factory wall texture.jpg'; + +import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; // Define Material type type Material = { @@ -58,14 +59,6 @@ const WallProperties = () => { setWallThickness(parseFloat(newValue)); }; - const handleAddMaterial = () => { - const newMaterial: Material = { - texture: defaultMaterial.texture, - textureName: `Material ${materials.length + 1}`, - }; - setMaterials([...materials, newMaterial]); - }; - const handleSelectMaterial = (material: Material) => { setSelectedMaterials((prev) => ({ ...prev, @@ -73,46 +66,26 @@ const WallProperties = () => { })); }; - const handleRemoveMaterial = (index: number) => { - const removedTexture = materials[index].texture; - - const updatedMaterials = materials.filter((_, i) => i !== index); - const newMaterials = updatedMaterials.length === 0 ? [defaultMaterial] : updatedMaterials; - setMaterials(newMaterials); - - setSelectedMaterials((prev) => { - const updated = { ...prev }; - ["side1", "side2"].forEach((side) => { - if (updated[side as "side1" | "side2"]?.texture === removedTexture) { - updated[side as "side1" | "side2"] = defaultMaterial; - } - }); - return updated; - }); - }; - return (
-
Wall
-
- handleHeightChange(val)} - /> - handleThicknessChange(val)} - /> -
- +
+
Wall
+
+ handleHeightChange(val)} + /> + handleThicknessChange(val)} + /> +
+
Materials
-
@@ -185,15 +158,6 @@ const WallProperties = () => {
{material.textureName}
- ); })} diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index b977781..cbbf2fe 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -276,7 +276,7 @@ export default function Builder() { - {/* */} + ); } diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index 8f1c2f2..ed3065d 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -148,7 +148,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin } if (toolMode === "Wall") { - drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } if (toolMode === "Floor") { diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 68402d9..19f0810 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -1,11 +1,11 @@ import * as THREE from 'three'; +import { useThree } from '@react-three/fiber'; import { useEffect, useMemo, useState } from "react"; -import * as Constants from '../../../types/world/worldConstants'; import { DragControls, Tube } from '@react-three/drei'; import { useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; -import { useWallStore } from '../../../store/builder/useWallStore'; -import { useThree } from '@react-three/fiber'; +import { useSceneContext } from '../../scene/sceneContext'; +import * as Constants from '../../../types/world/worldConstants'; interface LineProps { points: [Point, Point]; @@ -17,7 +17,8 @@ function Line({ points }: Readonly) { const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const [isDeletable, setIsDeletable] = useState(false); const { toolMode } = useToolMode(); - const { removeWallByPoints, setPosition } = useWallStore(); + const { wallStore } = useSceneContext(); + const { removeWallByPoints, setPosition } = wallStore(); const [dragOffset, setDragOffset] = useState(null); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); @@ -79,6 +80,7 @@ function Line({ points }: Readonly) { if (toolMode === '2D-Delete') { if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') { removeWallByPoints(points); + setHoveredLine(null); } gl.domElement.style.cursor = 'default'; } diff --git a/app/src/modules/builder/point/helpers/usePointSnapping.tsx b/app/src/modules/builder/point/helpers/usePointSnapping.tsx index 88c9890..c7d31cc 100644 --- a/app/src/modules/builder/point/helpers/usePointSnapping.tsx +++ b/app/src/modules/builder/point/helpers/usePointSnapping.tsx @@ -1,6 +1,5 @@ import * as THREE from 'three'; import { useCallback } from 'react'; -import { useWallStore } from '../../../../store/builder/useWallStore'; import { useSceneContext } from '../../../scene/sceneContext'; const POINT_SNAP_THRESHOLD = 0.5; // Distance threshold for snapping in meters @@ -12,9 +11,9 @@ const ANGLE_SNAP_DISTANCE_THRESHOLD = 0.5; // Distance threshold for snapping i const CAN_ANGLE_SNAP = true; // Whether snapping is enabled or not export const usePointSnapping = (currentPoint: { uuid: string, pointType: string, position: [number, number, number] } | null) => { - const { aisleStore } = useSceneContext(); + const { aisleStore, wallStore } = useSceneContext(); const { aisles, getConnectedPoints: getConnectedAislePoints } = aisleStore(); - const { walls, getConnectedPoints: getConnectedWallPoints } = useWallStore(); + const { walls, getConnectedPoints: getConnectedWallPoints } = wallStore(); // Wall Snapping diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 3545e99..a671806 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -6,7 +6,6 @@ import { DragControls } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { usePointSnapping } from './helpers/usePointSnapping'; -import { useWallStore } from '../../../store/builder/useWallStore'; import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; import { useParams } from 'react-router-dom'; import { createAisleApi } from '../../../services/factoryBuilder/aisle/createAisleApi'; @@ -20,9 +19,9 @@ function Point({ point }: { readonly point: Point }) { const [isHovered, setIsHovered] = useState(false); const [dragOffset, setDragOffset] = useState(null); const { toolMode } = useToolMode(); - const { aisleStore } = useSceneContext(); + const { aisleStore, wallStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); - const { setPosition: setWallPosition, removePoint: removeWallPoint } = useWallStore(); + const { setPosition: setWallPosition, removePoint: removeWallPoint } = wallStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { selectedVersionStore } = useVersionContext(); @@ -31,6 +30,10 @@ function Point({ point }: { readonly point: Point }) { const boxScale: [number, number, number] = Constants.pointConfig.boxScale; const colors = getColor(point); + useEffect(() => { + gl.domElement.style.cursor = 'default'; + }, [toolMode]) + function getColor(point: Point) { if (point.pointType === 'Aisle') { return { diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 6c2d858..4ada970 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -1,18 +1,25 @@ import * as THREE from 'three'; +import { Base } from '@react-three/csg'; import { useMemo, useRef, useState } from 'react'; -import * as Constants from '../../../../../types/world/worldConstants'; +import { Decal, MeshDiscardMaterial } from '@react-three/drei'; +import { useFrame, useThree } from '@react-three/fiber'; import defaultMaterial from '../../../../../assets/textures/floor/wall-tex.png'; import material1 from '../../../../../assets/textures/floor/factory wall texture.jpg'; -import { useWallStore } from '../../../../../store/builder/useWallStore'; + +import useModuleStore from '../../../../../store/useModuleStore'; +import { useSceneContext } from '../../../../scene/sceneContext'; import { useWallClassification } from './helpers/useWallClassification'; -import { useFrame, useThree } from '@react-three/fiber'; -import { useWallVisibility } from '../../../../../store/builder/store'; -import { Decal } from '@react-three/drei'; -import { Base } from '@react-three/csg'; +import { useToggleView, useWallVisibility } from '../../../../../store/builder/store'; +import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; +import * as Constants from '../../../../../types/world/worldConstants'; function Wall({ wall }: { readonly wall: Wall }) { - const { walls } = useWallStore(); + const { wallStore } = useSceneContext(); + const { walls } = wallStore(); + const { togglView } = useToggleView(); + const { setSelectedWall } = useBuilderStore(); + const { activeModule } = useModuleStore(); const { camera } = useThree(); const { wallVisibility } = useWallVisibility(); const { getWallType, isWallFlipped } = useWallClassification(walls); @@ -67,7 +74,7 @@ function Wall({ wall }: { readonly wall: Wall }) { new THREE.MeshStandardMaterial({ color: Constants.wallConfig.defaultColor, side: THREE.DoubleSide, - map: wall.outsideMaterial === 'Default Material`' ? defaultWallTexture : material1WallTexture, + map: wall.outsideMaterial === 'Default Material' ? defaultWallTexture : material1WallTexture, }), ]; }, [defaultWallTexture, material1WallTexture, wall]); @@ -100,6 +107,7 @@ function Wall({ wall }: { readonly wall: Wall }) { geometry={geometry} position={[centerX, centerY, centerZ]} rotation={[0, -angle, 0]} + userData={wall} > {materials.map((material, index) => ( @@ -112,6 +120,7 @@ function Wall({ wall }: { readonly wall: Wall }) { position={[decal.decalPosition[0], decal.decalPosition[1], wall.wallThickness / 2]} rotation={[0, 0, decal.decalRotation]} scale={[decal.decalScale, decal.decalScale, 0.001]} + userData={decal} > + { + if (visible && !togglView && activeModule === 'builder') { + setSelectedWall(e.object) + } + }} + onPointerMissed={() => { setSelectedWall(null) }} + > + + ); } diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index 37f07e0..b22d0e6 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -2,9 +2,10 @@ import React, { useEffect, useMemo } from 'react'; import { DoubleSide, RepeatWrapping, Shape, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from 'three'; import { Geometry } from '@react-three/csg'; import { Html, Extrude } from '@react-three/drei'; -import { useWallStore } from '../../../../store/builder/useWallStore' -import { useWallClassification } from './instance/helpers/useWallClassification'; +import { useLoader } from '@react-three/fiber'; +import { useSceneContext } from '../../../scene/sceneContext'; import { useToggleView } from '../../../../store/builder/store'; +import { useWallClassification } from './instance/helpers/useWallClassification'; import Line from '../../line/line'; import Point from '../../point/point'; import WallInstance from './instance/wallInstance'; @@ -12,10 +13,10 @@ import * as Constants from '../../../../types/world/worldConstants'; import texturePath from "../../../../assets/textures/floor/white.png"; import texturePathDark from "../../../../assets/textures/floor/black.png"; -import { useLoader } from '@react-three/fiber'; function WallInstances() { - const { walls } = useWallStore(); + const { wallStore } = useSceneContext(); + const { walls } = wallStore(); const { rooms } = useWallClassification(walls) const { toggleView } = useToggleView(); diff --git a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx index 61af916..a136a41 100644 --- a/app/src/modules/builder/wall/wallCreator/wallCreator.tsx +++ b/app/src/modules/builder/wall/wallCreator/wallCreator.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import * as Constants from '../../../../types/world/worldConstants'; -import { useWallStore } from '../../../../store/builder/useWallStore'; +import { useSceneContext } from '../../../scene/sceneContext'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceWall from './referenceWall'; @@ -16,7 +16,8 @@ function WallCreator() { const { toolMode } = useToolMode(); const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); - const { addWall, getWallPointById, removeWall, getWallByPoints } = useWallStore(); + const { wallStore } = useSceneContext(); + const { addWall, getWallPointById, removeWall, getWallByPoints } = wallStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); const { wallThickness, wallHeight, insideMaterial, outsideMaterial, snappedPosition, snappedPoint } = useBuilderStore(); diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index b3fe3c4..07ef700 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,7 +1,21 @@ +import { useEffect } from 'react'; +import { useToggleView } from '../../../store/builder/store' +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import WallCreator from './wallCreator/wallCreator' import WallInstances from './Instances/wallInstances' +import useModuleStore from '../../../store/useModuleStore'; function WallGroup() { + const { togglView } = useToggleView(); + const { setSelectedWall } = useBuilderStore(); + const { activeModule } = useModuleStore(); + + useEffect(() => { + if (togglView || activeModule !== 'builder') { + setSelectedWall(null); + } + }, [togglView, activeModule]) + return ( <> diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 276f0bf..1b91386 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle } = useBuilderStore(); + const { selectedAisle, selectedWall } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -40,6 +40,10 @@ export default function PostProcessing() { // console.log('selectedAisle: ', selectedAisle); }, [selectedAisle]) + useEffect(() => { + // console.log('selectedWall: ', selectedWall); + }, [selectedWall]) + return ( )} + {selectedWall && ( + + )} {deletableFloorItem && ( createAssetStore(), []); + const wallAssetStore = useMemo(() => createWallAssetStore(), []); + const wallStore = useMemo(() => createWallStore(), []); const aisleStore = useMemo(() => createAisleStore(), []); + const zoneStore = useMemo(() => createZoneStore(), []); + const floorStore = useMemo(() => createFloorStore(), []); const eventStore = useMemo(() => createEventStore(), []); const productStore = useMemo(() => createProductStore(), []); @@ -58,7 +70,11 @@ export function SceneProvider({ const clearStores = useMemo(() => () => { assetStore.getState().clearAssets(); + wallAssetStore.getState().clearWallAssets(); + wallStore.getState().clearWalls(); aisleStore.getState().clearAisles(); + zoneStore.getState().clearZones(); + floorStore.getState().clearFloors(); eventStore.getState().clearEvents(); productStore.getState().clearProducts(); materialStore.getState().clearMaterials(); @@ -67,12 +83,16 @@ export function SceneProvider({ conveyorStore.getState().clearConveyors(); vehicleStore.getState().clearVehicles(); storageUnitStore.getState().clearStorageUnits(); - }, [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); + }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); const contextValue = useMemo(() => ( { assetStore, + wallAssetStore, + wallStore, aisleStore, + zoneStore, + floorStore, eventStore, productStore, materialStore, @@ -84,7 +104,7 @@ export function SceneProvider({ clearStores, layout } - ), [assetStore, aisleStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]); + ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, clearStores, layout]); return ( diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 086a020..f59ab54 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -3,74 +3,58 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; interface BuilderState { - // Common properties - + // Point & Line Interaction hoveredPoint: Point | null; snappedPoint: Point | null; snappedPosition: [number, number, number] | null; - hoveredLine: [Point, Point] | null; - // Wall - + // Wall Settings + selectedWall: Object3D | null; wallThickness: number; wallHeight: number; outsideMaterial: string; insideMaterial: string; - setWallThickness: (thickness: number) => void; - setWallHeight: (height: number) => void; - setWallMaterial: (material: string, side: 'inside' | 'outside') => void; - - // Aisle - + // Aisle General selectedAisle: Object3D | null; - aisleType: AisleTypes; aisleWidth: number; aisleColor: AisleColors; - // Dashed aisle properties + // Aisle Specific Styles dashLength: number; gapLength: number; - - // Dotted aisle properties dotRadius: number; - - // Arrows aisle properties aisleLength: number; - - // Junction aisle properties isFlipped: boolean; - // Setters for common properties - + // Setters - Point/Line setHoveredPoint: (point: Point | null) => void; setSnappedPoint: (point: Point | null) => void; setSnappedPosition: (position: [number, number, number] | null) => void; - setHoveredLine: (line: [Point, Point] | null) => void; - setSelectedAisle: (aisle: Object3D | null) => void; + // Setters - Wall + setSelectedWall: (wall: Object3D | null) => void; + setWallThickness: (thickness: number) => void; + setWallHeight: (height: number) => void; + setWallMaterial: (material: string, side: 'inside' | 'outside') => void; + // Setters - Aisle General + setSelectedAisle: (aisle: Object3D | null) => void; setAisleType: (type: AisleTypes) => void; setAisleWidth: (width: number) => void; setAisleColor: (color: AisleColors) => void; - // Setters for dashed aisle + // Setters - Aisle Specific setDashLength: (length: number) => void; setGapLength: (length: number) => void; - - // Setters for dotted aisle setDotRadius: (radius: number) => void; - - // Setters for arrows aisle setAisleLength: (length: number) => void; - - // Setters for junction aisle setIsFlipped: (isFlipped: boolean) => void; - // Batch setters + // Batch Setters setDashedAisleProperties: (width: number, dashLength: number, gapLength: number) => void; setDottedAisleProperties: (width: number, dotRadius: number, gapLength: number) => void; setArrowsAisleProperties: (width: number, aisleLength: number, gapLength: number) => void; @@ -79,20 +63,62 @@ interface BuilderState { export const useBuilderStore = create()( immer((set) => ({ - // Default values - + // === Defaults === hoveredPoint: null, snappedPoint: null, snappedPosition: null, - hoveredLine: null, - // Wall - + selectedWall: null, wallThickness: 0.5, wallHeight: 7, outsideMaterial: 'Default Material', - insideMaterial: 'Default Material', + insideMaterial: 'Material 1', + + selectedAisle: null, + aisleType: 'solid-aisle', + aisleWidth: 0.1, + aisleColor: 'yellow', + + dashLength: 0.5, + gapLength: 0.3, + dotRadius: 0.1, + aisleLength: 0.6, + isFlipped: false, + + // === Setters: Point/Line === + + setHoveredPoint: (point: Point | null) => { + set((state) => { + state.hoveredPoint = point; + }); + }, + + setSnappedPoint: (point: Point | null) => { + set((state) => { + state.snappedPoint = point; + }); + }, + + setSnappedPosition: (position: [number, number, number] | null) => { + set((state) => { + state.snappedPosition = position; + }); + }, + + setHoveredLine: (line: [Point, Point] | null) => { + set((state) => { + state.hoveredLine = line; + }) + }, + + // === Setters: Wall === + + setSelectedWall: (wall: Object3D | null) => { + set((state) => { + state.selectedWall = wall; + }) + }, setWallThickness: (thickness: number) => { set((state) => { @@ -113,44 +139,7 @@ export const useBuilderStore = create()( }); }, - // Aisle - - selectedAisle: null, - - aisleType: 'solid-aisle', - aisleWidth: 0.1, - aisleColor: 'yellow', - dashLength: 0.5, - gapLength: 0.3, - dotRadius: 0.1, - aisleLength: 0.6, - isFlipped: false, - - // Individual setters - - setHoveredPoint: (point: Point | null) => { - set((state) => { - state.hoveredPoint = point; - }); - }, - - setHoveredLine: (line: [Point, Point] | null) => { - set((state) => { - state.hoveredLine = line; - }) - }, - - setSnappedPoint: (point: Point | null) => { - set((state) => { - state.snappedPoint = point; - }); - }, - - setSnappedPosition: (position: [number, number, number] | null) => { - set((state) => { - state.snappedPosition = position; - }); - }, + // === Setters: Aisle General === setSelectedAisle: (aisle: Object3D | null) => { set((state) => { @@ -163,73 +152,78 @@ export const useBuilderStore = create()( state.aisleType = type; }); }, + setAisleWidth: (width) => { set((state) => { state.aisleWidth = width; }); }, + setAisleColor: (color) => { set((state) => { state.aisleColor = color; }); }, + + // === Setters: Aisle Specific === + setDashLength: (length) => { set((state) => { state.dashLength = length; }); }, + setGapLength: (length) => { set((state) => { state.gapLength = length; }); }, + setDotRadius: (radius) => { set((state) => { state.dotRadius = radius; }); }, + setAisleLength: (length) => { set((state) => { state.aisleLength = length; }); }, + setIsFlipped: (isFlipped) => { set((state) => { state.isFlipped = isFlipped; }); }, - // Batch setters - setDashedAisleProperties: (width, dashLength, gapLength) => { - set((state) => { - state.aisleType = 'dashed-aisle'; - state.aisleWidth = width; - state.dashLength = dashLength; - state.gapLength = gapLength; - }); - }, - setDottedAisleProperties: (width, dotRadius, gapLength) => { - set((state) => { - state.aisleType = 'dotted-aisle'; - state.aisleWidth = width; - state.dotRadius = dotRadius; - state.gapLength = gapLength; - }); - }, - setArrowsAisleProperties: (width, aisleLength, gapLength) => { - set((state) => { - state.aisleType = 'arrows-aisle'; - state.aisleWidth = width; - state.aisleLength = aisleLength; - state.gapLength = gapLength; - }); - }, - setAisleProperties: (type, width, color) => { - set((state) => { - state.aisleType = type; - state.aisleWidth = width; - state.aisleColor = color; - }); - } + // === Batch Setters === + + setDashedAisleProperties: (width, dashLength, gapLength) => set((state) => { + state.aisleType = 'dashed-aisle'; + state.aisleWidth = width; + state.dashLength = dashLength; + state.gapLength = gapLength; + }), + + setDottedAisleProperties: (width, dotRadius, gapLength) => set((state) => { + state.aisleType = 'dotted-aisle'; + state.aisleWidth = width; + state.dotRadius = dotRadius; + state.gapLength = gapLength; + }), + + setArrowsAisleProperties: (width, aisleLength, gapLength) => set((state) => { + state.aisleType = 'arrows-aisle'; + state.aisleWidth = width; + state.aisleLength = aisleLength; + state.gapLength = gapLength; + }), + + setAisleProperties: (type, width, color) => set((state) => { + state.aisleType = type; + state.aisleWidth = width; + state.aisleColor = color; + }) })) -); \ No newline at end of file +); diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts new file mode 100644 index 0000000..4c89333 --- /dev/null +++ b/app/src/store/builder/useFloorStore.ts @@ -0,0 +1,90 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface FloorStore { + floors: Floor[]; + setFloors: (floors: Floor[]) => void; + addFloor: (floor: Floor) => void; + updateFloor: (uuid: string, updated: Partial) => void; + removeFloor: (uuid: string) => void; + removePointFromFloors: (pointUuid: string) => void; + clearFloors: () => void; + setIsBeveled: (uuid: string, isBeveled: boolean) => void; + setBevelStrength: (uuid: string, strength: number) => void; + setDepth: (uuid: string, depth: number) => void; + setMaterial: (uuid: string, sideMaterial: string, topMaterial: string) => void; + + getFloorById: (uuid: string) => Floor | undefined; +} + +export const createFloorStore = () => { + return create()( + immer((set, get) => ({ + floors: [], + + setFloors: (floors) => set(state => { + state.floors = floors; + }), + + addFloor: (floor) => set(state => { + state.floors.push(floor); + }), + + updateFloor: (uuid, updated) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + Object.assign(floor, updated); + } + }), + + removeFloor: (uuid) => set(state => { + state.floors = state.floors.filter(f => f.floorUuid !== uuid); + }), + + removePointFromFloors: (pointUuid) => set(state => { + for (const floor of state.floors) { + floor.points = floor.points.filter(p => p.pointUuid !== pointUuid); + } + }), + + clearFloors: () => set(state => { + state.floors = []; + }), + + setIsBeveled: (uuid, isBeveled) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.isBeveled = isBeveled; + } + }), + + setBevelStrength: (uuid, strength) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.bevelStrength = strength; + } + }), + + setDepth: (uuid, depth) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.floorDepth = depth; + } + }), + + setMaterial: (uuid, sideMaterial, topMaterial) => set(state => { + const floor = state.floors.find(f => f.floorUuid === uuid); + if (floor) { + floor.sideMaterial = sideMaterial; + floor.topMaterial = topMaterial; + } + }), + + getFloorById: (uuid) => { + return get().floors.find(f => f.floorUuid === uuid); + }, + })) + ); +}; + +export type FloorStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallAssetStore.ts b/app/src/store/builder/useWallAssetStore.ts new file mode 100644 index 0000000..408aade --- /dev/null +++ b/app/src/store/builder/useWallAssetStore.ts @@ -0,0 +1,82 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface WallAssetStore { + wallAssets: WallAsset[]; + setWallAssets: (assets: WallAsset[]) => void; + addWallAsset: (asset: WallAsset) => void; + updateWallAsset: (uuid: string, updated: Partial) => void; + removeWallAsset: (uuid: string) => void; + clearWallAssets: () => void; + + setVisibility: (uuid: string, isVisible: boolean) => void; + setLock: (uuid: string, isLocked: boolean) => void; + setOpacity: (uuid: string, opacity: number) => void; + + getWallAssetById: (uuid: string) => WallAsset | undefined; + getAssetsByWall: (wallUuid: string) => WallAsset[]; +} + +export const createWallAssetStore = () => { + return create()( + immer((set, get) => ({ + wallAssets: [], + + setWallAssets: (assets) => set(state => { + state.wallAssets = assets; + }), + + addWallAsset: (asset) => set(state => { + state.wallAssets.push(asset); + }), + + updateWallAsset: (uuid, updated) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + Object.assign(asset, updated); + } + }), + + removeWallAsset: (uuid) => set(state => { + state.wallAssets = state.wallAssets.filter(a => a.modelUuid !== uuid); + }), + + clearWallAssets: () => { + set(state => { + state.wallAssets = []; + }) + }, + + setVisibility: (uuid, isVisible) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.isVisible = isVisible; + } + }), + + setLock: (uuid, isLocked) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.isLocked = isLocked; + } + }), + + setOpacity: (uuid, opacity) => set(state => { + const asset = state.wallAssets.find(a => a.modelUuid === uuid); + if (asset) { + asset.opacity = opacity; + } + }), + + getWallAssetById: (uuid) => { + return get().wallAssets.find(a => a.modelUuid === uuid); + }, + + getAssetsByWall: (wallUuid) => { + return get().wallAssets.filter(a => a.wallUuid === wallUuid); + }, + })) + ); +}; + +export type WallAssetStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallStore.ts b/app/src/store/builder/useWallStore.ts new file mode 100644 index 0000000..3547330 --- /dev/null +++ b/app/src/store/builder/useWallStore.ts @@ -0,0 +1,211 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface WallStore { + walls: Wall[]; + setWalls: (walls: Wall[]) => void; + addWall: (wall: Wall) => void; + updateWall: (uuid: string, updated: Partial) => void; + removeWall: (uuid: string) => void; + clearWalls: () => void; + removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; + addDecal: (wallUuid: string, decal: Decal) => void; + updateDecal: (decalUuid: string, decal: Decal) => void; + removeDecal: (decalUuid: string) => void; + updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; + updateDecalRotation: (decalUuid: string, rotation: number) => void; + updateDecalScale: (decalUuid: string, scale: number) => void; + + removePoint: (pointUuid: string) => Wall[]; + setPosition: (pointUuid: string, position: [number, number, number]) => void; + setLayer: (pointUuid: string, layer: number) => void; + + getWallById: (uuid: string) => Wall | undefined; + getWallByPointId: (uuid: string) => Wall | undefined; + getWallByPoints: (points: Point[]) => Wall | undefined; + getWallPointById: (uuid: string) => Point | undefined; + getConnectedPoints: (uuid: string) => Point[]; +} + +export const createWallStore = () => { + return create()( + immer((set, get) => ({ + walls: [], + + setWalls: (walls) => set((state) => { + state.walls = walls; + }), + + addWall: (wall) => set((state) => { + state.walls.push(wall); + }), + + updateWall: (uuid, updated) => set((state) => { + const wall = state.walls.find(w => w.wallUuid === uuid); + if (wall) { + Object.assign(wall, updated); + } + }), + + removeWall: (uuid) => set((state) => { + state.walls = state.walls.filter(w => w.wallUuid !== uuid); + }), + + clearWalls: () => { + set((state) => { + state.walls = []; + }) + }, + + removeWallByPoints: (points) => { + let removedWall: Wall | undefined; + const [pointA, pointB] = points; + + set((state) => { + state.walls = state.walls.filter(wall => { + const wallPoints = wall.points.map(p => p.pointUuid); + const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid); + + if (hasBothPoints) { + removedWall = JSON.parse(JSON.stringify(wall)); + return false; + } + return true; + }); + }); + + return removedWall; + }, + + addDecal: (wallUuid, decal) => set((state) => { + const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid); + if (wallToUpdate) { + wallToUpdate.decals.push(decal); + } + }), + + updateDecal: (decalUuid, decal) => set((state) => { + for (const wall of state.walls) { + const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid); + if (decalToUpdate) { + Object.assign(decalToUpdate, decal); + } + } + }), + + removeDecal: (decalUuid) => set((state) => { + for (const wall of state.walls) { + wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid); + } + }), + + updateDecalPosition: (decalUuid, position) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalPosition = position; + break; + } + } + }), + + updateDecalRotation: (decalUuid, rotation) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalRotation = rotation; + break; + } + } + }), + + updateDecalScale: (decalUuid, scale) => set((state) => { + for (const wall of state.walls) { + const decal = wall.decals.find(d => d.decalUuid === decalUuid); + if (decal) { + decal.decalScale = scale; + break; + } + } + }), + + removePoint: (pointUuid) => { + const removedWalls: Wall[] = []; + set((state) => { + state.walls = state.walls.filter((wall) => { + const hasPoint = wall.points.some(p => p.pointUuid === pointUuid); + if (hasPoint) { + removedWalls.push(JSON.parse(JSON.stringify(wall))); + return false; + } + return true; + }); + }); + return removedWalls; + }, + + setPosition: (pointUuid, position) => set((state) => { + for (const wall of state.walls) { + const point = wall.points.find(p => p.pointUuid === pointUuid); + if (point) { + point.position = position; + } + } + }), + + setLayer: (pointUuid, layer) => set((state) => { + for (const wall of state.walls) { + const point = wall.points.find(p => p.pointUuid === pointUuid); + if (point) { + point.layer = layer; + } + } + }), + + getWallById: (uuid) => { + return get().walls.find(w => w.wallUuid === uuid); + }, + + getWallByPointId: (uuid) => { + for (const wall of get().walls) { + if (wall.points.some(p => p.pointUuid === uuid)) { + return wall; + } + } + return undefined; + }, + + getWallByPoints: (point) => { + for (const wall of get().walls) { + if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) && + ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) { + return wall; + } + } + return undefined; + }, + + getWallPointById: (uuid) => { + for (const wall of get().walls) { + const point = wall.points.find(p => p.pointUuid === uuid); + if (point) return point; + } + return undefined; + }, + + getConnectedPoints: (uuid) => { + const connected: Point[] = []; + for (const wall of get().walls) { + for (const point of wall.points) { + if (point.pointUuid === uuid) { + connected.push(...wall.points.filter(p => p.pointUuid !== uuid)); + } + } + } + return connected; + }, + })) + ) +} + +export type WallStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/store/builder/useWallStore.tsx b/app/src/store/builder/useWallStore.tsx deleted file mode 100644 index 4f57849..0000000 --- a/app/src/store/builder/useWallStore.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; - -interface WallStore { - walls: Wall[]; - setWalls: (walls: Wall[]) => void; - addWall: (wall: Wall) => void; - updateWall: (uuid: string, updated: Partial) => void; - removeWall: (uuid: string) => void; - removeWallByPoints: (Points: [Point, Point]) => Wall | undefined; - addDecal: (wallUuid: string, decal: Decal) => void; - updateDecal: (decalUuid: string, decal: Decal) => void; - removeDecal: (decalUuid: string) => void; - updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void; - updateDecalRotation: (decalUuid: string, rotation: number) => void; - updateDecalScale: (decalUuid: string, scale: number) => void; - - removePoint: (pointUuid: string) => Wall[]; - setPosition: (pointUuid: string, position: [number, number, number]) => void; - setLayer: (pointUuid: string, layer: number) => void; - - getWallById: (uuid: string) => Wall | undefined; - getWallByPointId: (uuid: string) => Wall | undefined; - getWallByPoints: (points: Point[]) => Wall | undefined; - getWallPointById: (uuid: string) => Point | undefined; - getConnectedPoints: (uuid: string) => Point[]; -} - -export const useWallStore = create()( - immer((set, get) => ({ - walls: [], - - setWalls: (walls) => set((state) => { - state.walls = walls; - }), - - addWall: (wall) => set((state) => { - state.walls.push(wall); - }), - - updateWall: (uuid, updated) => set((state) => { - const wall = state.walls.find(w => w.wallUuid === uuid); - if (wall) { - Object.assign(wall, updated); - } - }), - - removeWall: (uuid) => set((state) => { - state.walls = state.walls.filter(w => w.wallUuid !== uuid); - }), - - removeWallByPoints: (points) => { - let removedWall: Wall | undefined; - const [pointA, pointB] = points; - - set((state) => { - state.walls = state.walls.filter(wall => { - const wallPoints = wall.points.map(p => p.pointUuid); - const hasBothPoints = wallPoints.includes(pointA.pointUuid) && wallPoints.includes(pointB.pointUuid); - - if (hasBothPoints) { - removedWall = JSON.parse(JSON.stringify(wall)); - return false; - } - return true; - }); - }); - - return removedWall; - }, - - addDecal: (wallUuid, decal) => set((state) => { - const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid); - if (wallToUpdate) { - wallToUpdate.decals.push(decal); - } - }), - - updateDecal: (decalUuid, decal) => set((state) => { - for (const wall of state.walls) { - const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid); - if (decalToUpdate) { - Object.assign(decalToUpdate, decal); - } - } - }), - - removeDecal: (decalUuid) => set((state) => { - for (const wall of state.walls) { - wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid); - } - }), - - updateDecalPosition: (decalUuid, position) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalPosition = position; - break; - } - } - }), - - updateDecalRotation: (decalUuid, rotation) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalRotation = rotation; - break; - } - } - }), - - updateDecalScale: (decalUuid, scale) => set((state) => { - for (const wall of state.walls) { - const decal = wall.decals.find(d => d.decalUuid === decalUuid); - if (decal) { - decal.decalScale = scale; - break; - } - } - }), - - removePoint: (pointUuid) => { - const removedWalls: Wall[] = []; - set((state) => { - state.walls = state.walls.filter((wall) => { - const hasPoint = wall.points.some(p => p.pointUuid === pointUuid); - if (hasPoint) { - removedWalls.push(JSON.parse(JSON.stringify(wall))); - return false; - } - return true; - }); - }); - return removedWalls; - }, - - setPosition: (pointUuid, position) => set((state) => { - for (const wall of state.walls) { - const point = wall.points.find(p => p.pointUuid === pointUuid); - if (point) { - point.position = position; - } - } - }), - - setLayer: (pointUuid, layer) => set((state) => { - for (const wall of state.walls) { - const point = wall.points.find(p => p.pointUuid === pointUuid); - if (point) { - point.layer = layer; - } - } - }), - - getWallById: (uuid) => { - return get().walls.find(w => w.wallUuid === uuid); - }, - - getWallByPointId: (uuid) => { - for (const wall of get().walls) { - if (wall.points.some(p => p.pointUuid === uuid)) { - return wall; - } - } - return undefined; - }, - - getWallByPoints: (point) => { - for (const wall of get().walls) { - if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) && - ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) { - return wall; - } - } - return undefined; - }, - - getWallPointById: (uuid) => { - for (const wall of get().walls) { - const point = wall.points.find(p => p.pointUuid === uuid); - if (point) return point; - } - return undefined; - }, - - getConnectedPoints: (uuid) => { - const connected: Point[] = []; - for (const wall of get().walls) { - for (const point of wall.points) { - if (point.pointUuid === uuid) { - connected.push(...wall.points.filter(p => p.pointUuid !== uuid)); - } - } - } - return connected; - }, - })) -); diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts new file mode 100644 index 0000000..ee3c736 --- /dev/null +++ b/app/src/store/builder/useZoneStore.ts @@ -0,0 +1,74 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface ZoneStore { + zones: Zone[]; + setZones: (zones: Zone[]) => void; + addZone: (zone: Zone) => void; + updateZone: (uuid: string, updated: Partial) => void; + removeZone: (uuid: string) => void; + removePointFromZones: (pointUuid: string) => void; + clearZones: () => void; + setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; + setColor: (uuid: string, color: string) => void; + + getZoneById: (uuid: string) => Zone | undefined; +} + +export const createZoneStore = () => { + return create()( + immer((set, get) => ({ + zones: [], + + setZones: (zones) => set(state => { + state.zones = zones; + }), + + addZone: (zone) => set(state => { + state.zones.push(zone); + }), + + updateZone: (uuid, updated) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + Object.assign(zone, updated); + } + }), + + removeZone: (uuid) => set(state => { + state.zones = state.zones.filter(z => z.zoneUuid !== uuid); + }), + + removePointFromZones: (pointUuid) => set(state => { + for (const zone of state.zones) { + zone.points = zone.points.filter(p => p.pointUuid !== pointUuid); + } + }), + + clearZones: () => set(state => { + state.zones = []; + }), + + setViewPort: (uuid, position, target) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.viewPortPosition = position; + zone.viewPortTarget = target; + } + }), + + setColor: (uuid, color) => set(state => { + const zone = state.zones.find(z => z.zoneUuid === uuid); + if (zone) { + zone.zoneColor = color; + } + }), + + getZoneById: (uuid) => { + return get().zones.find(z => z.zoneUuid === uuid); + }, + })) + ); +}; + +export type ZoneStoreType = ReturnType; \ No newline at end of file diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 51f32df..6b24256 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -1657,8 +1657,13 @@ .sidebar-right-wrapper { .wall-properties-container { + .wall-properties-section{ + padding: 14px; + padding-bottom: 0; + margin-bottom: 8px; + } .header { - color: var(--background-color-button); + color: var(--text-color); } .wall-properties { @@ -1692,7 +1697,7 @@ flex-direction: column; align-items: center; gap: 15px; - background: var(--Grays-Gray-6, #f2f2f7); + background: var(--background-color-secondary); padding: 18px 25px; .sides-wrapper { @@ -1736,8 +1741,10 @@ } .preview { - width: 90%; + width: 100%; height: 111px; + border-radius: 20px; + overflow: hidden; img { width: 100%; @@ -1750,7 +1757,8 @@ .materials { max-height: 250px; overflow: auto; - margin-bottom: 6px; + margin-top: 12px; + margin-bottom: 16px; padding: 0 12px; .material-container { From 08208528a5a96590d58563b69cbee0cdfedc4d34 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:20:35 +0530 Subject: [PATCH 4/7] Add decal management functionality and refactor wall components --- .../modules/builder/Decal/decalInstance.tsx | 48 +++++++++++++++++ .../builder/wall/Instances/instance/wall.tsx | 54 ++++++++++--------- .../builder/wall/Instances/wallInstances.tsx | 2 +- app/src/modules/builder/wall/wallGroup.tsx | 3 +- .../scene/postProcessing/postProcessing.tsx | 17 +++++- app/src/store/builder/useBuilderStore.ts | 16 ++++++ app/src/types/builderTypes.d.ts | 11 ++++ 7 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 app/src/modules/builder/Decal/decalInstance.tsx diff --git a/app/src/modules/builder/Decal/decalInstance.tsx b/app/src/modules/builder/Decal/decalInstance.tsx new file mode 100644 index 0000000..6ed0490 --- /dev/null +++ b/app/src/modules/builder/Decal/decalInstance.tsx @@ -0,0 +1,48 @@ +import * as THREE from 'three'; +import { Decal } from '@react-three/drei' +import { useLoader } from '@react-three/fiber'; +import { useToggleView } from '../../../store/builder/store'; +import { useBuilderStore } from '../../../store/builder/useBuilderStore'; + +import defaultMaterial from '../../../assets/textures/floor/wall-tex.png'; +import useModuleStore from '../../../store/useModuleStore'; + +function DecalInstance({ visible = true, decal }: { visible?: boolean, decal: Decal }) { + const { setSelectedWall, selectedDecal, setSelectedDecal } = useBuilderStore(); + const { togglView } = useToggleView(); + const { activeModule } = useModuleStore(); + const material = useLoader(THREE.TextureLoader, defaultMaterial); + + return ( + { + if (visible && !togglView && activeModule === 'builder') { + if (e.object.userData.decalUuid) { + setSelectedDecal(e.object); + setSelectedWall(null); + } + } + }} + onPointerMissed={() => { + if (selectedDecal && selectedDecal.userData.decalUuid === decal.decalUuid) { + setSelectedDecal(null); + } + }} + > + + + ) +} + +export default DecalInstance \ No newline at end of file diff --git a/app/src/modules/builder/wall/Instances/instance/wall.tsx b/app/src/modules/builder/wall/Instances/instance/wall.tsx index 4ada970..037816b 100644 --- a/app/src/modules/builder/wall/Instances/instance/wall.tsx +++ b/app/src/modules/builder/wall/Instances/instance/wall.tsx @@ -13,12 +13,13 @@ import { useWallClassification } from './helpers/useWallClassification'; import { useToggleView, useWallVisibility } from '../../../../../store/builder/store'; import { useBuilderStore } from '../../../../../store/builder/useBuilderStore'; import * as Constants from '../../../../../types/world/worldConstants'; +import DecalInstance from '../../../Decal/decalInstance'; function Wall({ wall }: { readonly wall: Wall }) { const { wallStore } = useSceneContext(); - const { walls } = wallStore(); + const { walls, addDecal } = wallStore(); + const { selectedWall, setSelectedWall, setSelectedDecal } = useBuilderStore(); const { togglView } = useToggleView(); - const { setSelectedWall } = useBuilderStore(); const { activeModule } = useModuleStore(); const { camera } = useThree(); const { wallVisibility } = useWallVisibility(); @@ -112,25 +113,6 @@ function Wall({ wall }: { readonly wall: Wall }) { {materials.map((material, index) => ( ))} - - {wall.decals.map((decal) => { - return ( - - - - ) - })} { if (visible && !togglView && activeModule === 'builder') { - setSelectedWall(e.object) + if (e.object.userData.wallUuid) { + setSelectedWall(e.object); + setSelectedDecal(null); + + if (wall.decals.length > 0) return; + const decal: Decal = { + decalUuid: THREE.MathUtils.generateUUID(), + decalName: 'Decal', + decalId: 'Default Decal', + decalPosition: [0, 0, wall.wallThickness / 2 + 0.001], + decalRotation: 0, + decalScale: 1, + decalType: { type: 'Wall', wallUuid: wall.wallUuid } + } + addDecal(wall.wallUuid, decal); + + } + } + }} + onPointerMissed={() => { + if (selectedWall && selectedWall.userData.wallUuid === wall.wallUuid) { + setSelectedWall(null); } }} - onPointerMissed={() => { setSelectedWall(null) }} > + + {wall.decals.map((decal) => ( + + ))} ); diff --git a/app/src/modules/builder/wall/Instances/wallInstances.tsx b/app/src/modules/builder/wall/Instances/wallInstances.tsx index b22d0e6..4d5da1e 100644 --- a/app/src/modules/builder/wall/Instances/wallInstances.tsx +++ b/app/src/modules/builder/wall/Instances/wallInstances.tsx @@ -42,7 +42,7 @@ function WallInstances() { return ( <> - {!toggleView && ( + {!toggleView && walls.length > 1 && ( <> diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index 07ef700..aae36b9 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -7,12 +7,13 @@ import useModuleStore from '../../../store/useModuleStore'; function WallGroup() { const { togglView } = useToggleView(); - const { setSelectedWall } = useBuilderStore(); + const { setSelectedWall, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); useEffect(() => { if (togglView || activeModule !== 'builder') { setSelectedWall(null); + setSelectedDecal(null); } }, [togglView, activeModule]) diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index 1b91386..25d0e0c 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -15,7 +15,7 @@ export default function PostProcessing() { const { selectedWallItem } = useSelectedWallItem(); const { selectedFloorItem } = useSelectedFloorItem(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedAisle, selectedWall } = useBuilderStore(); + const { selectedAisle, selectedWall, selectedDecal } = useBuilderStore(); function flattenChildren(children: any[]) { const allChildren: any[] = []; @@ -85,6 +85,21 @@ export default function PostProcessing() { xRay={true} /> )} + {selectedDecal && ( + + )} {deletableFloorItem && ( void; setWallMaterial: (material: string, side: 'inside' | 'outside') => void; + // Setters - Decal + setSelectedDecal: (decal: Object3D | null) => void; + // Setters - Aisle General setSelectedAisle: (aisle: Object3D | null) => void; setAisleType: (type: AisleTypes) => void; @@ -75,6 +81,8 @@ export const useBuilderStore = create()( outsideMaterial: 'Default Material', insideMaterial: 'Material 1', + selectedDecal: null, + selectedAisle: null, aisleType: 'solid-aisle', aisleWidth: 0.1, @@ -139,6 +147,14 @@ export const useBuilderStore = create()( }); }, + // === Setters: Decal === + + setSelectedDecal: (decal: Object3D | null) => { + set((state) => { + state.selectedDecal = decal; + }) + }, + // === Setters: Aisle General === setSelectedAisle: (aisle: Object3D | null) => { diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index decde1d..17349d7 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -80,11 +80,22 @@ interface Decal { decalUuid: string; decalName: string; decalId: string; + decalType: WallDecal | FloorDecal; decalPosition: [number, number, number]; decalRotation: number; decalScale: number; } +interface WallDecal { + type: 'Wall'; + wallUuid: string; +} + +interface FloorDecal { + type: 'Floor'; + floorUuid: string; +} + interface Wall { wallUuid: string; points: [Point, Point]; From d8a793c4216de2812baae9c4f863019ec9dbc942 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:32:36 +0530 Subject: [PATCH 5/7] Comment out WallGroup component and clean up drawWall function call --- app/src/modules/builder/builder.tsx | 2 +- app/src/modules/builder/groups/floorPlanGroup.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index cbbf2fe..b977781 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -276,7 +276,7 @@ export default function Builder() { - + {/* */} ); } diff --git a/app/src/modules/builder/groups/floorPlanGroup.tsx b/app/src/modules/builder/groups/floorPlanGroup.tsx index ed3065d..8f1c2f2 100644 --- a/app/src/modules/builder/groups/floorPlanGroup.tsx +++ b/app/src/modules/builder/groups/floorPlanGroup.tsx @@ -148,7 +148,7 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin } if (toolMode === "Wall") { - // drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); + drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket, projectId, selectedVersion?.versionId || '',); } if (toolMode === "Floor") { From 9696bc0f1ebbdf3b83b2233a01892b064e519f31 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 25 Jun 2025 17:39:28 +0530 Subject: [PATCH 6/7] Refactor drawWall function for improved readability and maintainability --- .../builder/geomentries/lines/drawWall.ts | 369 ++++++++---------- 1 file changed, 170 insertions(+), 199 deletions(-) diff --git a/app/src/modules/builder/geomentries/lines/drawWall.ts b/app/src/modules/builder/geomentries/lines/drawWall.ts index fb6cf10..80333ed 100644 --- a/app/src/modules/builder/geomentries/lines/drawWall.ts +++ b/app/src/modules/builder/geomentries/lines/drawWall.ts @@ -14,234 +14,205 @@ import { Socket } from "socket.io-client"; import { getUserData } from "../../../../functions/getUserData"; async function drawWall( - raycaster: THREE.Raycaster, - plane: Types.RefMesh, - floorPlanGroupPoint: Types.RefGroup, - snappedPoint: Types.RefVector3, - isSnapped: Types.RefBoolean, - isSnappedUUID: Types.RefString, - line: Types.RefLine, - ispreSnapped: Types.RefBoolean, - anglesnappedPoint: Types.RefVector3, - isAngleSnapped: Types.RefBoolean, - lines: Types.RefLines, - floorPlanGroupLine: Types.RefGroup, - floorPlanGroup: Types.RefGroup, - ReferenceLineMesh: Types.RefMesh, - LineCreated: Types.RefBoolean, - currentLayerPoint: Types.RefMeshArray, - dragPointControls: Types.RefDragControl, - setNewLines: any, - setDeletedLines: any, - activeLayer: Types.Number, - socket: Socket, - projectId?: string, - versionId?: string, + raycaster: THREE.Raycaster, + plane: Types.RefMesh, + floorPlanGroupPoint: Types.RefGroup, + snappedPoint: Types.RefVector3, + isSnapped: Types.RefBoolean, + isSnappedUUID: Types.RefString, + line: Types.RefLine, + ispreSnapped: Types.RefBoolean, + anglesnappedPoint: Types.RefVector3, + isAngleSnapped: Types.RefBoolean, + lines: Types.RefLines, + floorPlanGroupLine: Types.RefGroup, + floorPlanGroup: Types.RefGroup, + ReferenceLineMesh: Types.RefMesh, + LineCreated: Types.RefBoolean, + currentLayerPoint: Types.RefMeshArray, + dragPointControls: Types.RefDragControl, + setNewLines: any, + setDeletedLines: any, + activeLayer: Types.Number, + socket: Socket, + projectId?: string, + versionId?: string, ): Promise { - const { userId, organization, email } = getUserData(); - ////////// Creating lines Based on the positions clicked ////////// + const { userId, organization } = getUserData(); + ////////// Creating lines Based on the positions clicked ////////// - ////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// + ////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// - if (!plane.current) return; - let intersects = raycaster.intersectObject(plane.current, true); + if (!plane.current) return; + let intersects = raycaster.intersectObject(plane.current, true); - let intersectsLines = raycaster.intersectObjects( - floorPlanGroupLine.current.children, - true - ); - let intersectsPoint = raycaster.intersectObjects( - floorPlanGroupPoint.current.children, - true - ); + let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); + let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true); - const VisibleintersectsPoint = intersectsPoint.find( - (intersect) => intersect.object.visible - ); - const visibleIntersect = intersectsLines.find( - (intersect) => - intersect.object.visible && - intersect.object.name !== CONSTANTS.lineConfig.referenceName && - intersect.object.userData.linePoints[0][3] === - CONSTANTS.lineConfig.wallName - ); + const VisibleintersectsPoint = intersectsPoint.find((intersect) => intersect.object.visible); + const visibleIntersect = intersectsLines.find( + (intersect) => + intersect.object.visible && + intersect.object.name !== CONSTANTS.lineConfig.referenceName && + intersect.object.userData.linePoints[0][3] === + CONSTANTS.lineConfig.wallName + ); - if ( - (intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && - intersectsLines.length > 0 && - !isSnapped.current && - !ispreSnapped.current - ) { - ////////// Clicked on a preexisting Line ////////// + if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) { + ////////// Clicked on a preexisting Line ////////// - if (visibleIntersect && intersects) { - let IntersectsPoint = new THREE.Vector3( - intersects[0].point.x, - 0.01, - intersects[0].point.z - ); + if (visibleIntersect && intersects) { + let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z); - if (isAngleSnapped.current && anglesnappedPoint.current) { - IntersectsPoint = anglesnappedPoint.current; - } - if (visibleIntersect.object instanceof THREE.Mesh) { - const ThroughPoint = - visibleIntersect.object.geometry.parameters.path.getPoints( - CONSTANTS.lineConfig.lineIntersectionPoints - ); - let intersectionPoint = getClosestIntersection( - ThroughPoint, - IntersectsPoint - ); + if (isAngleSnapped.current && anglesnappedPoint.current) { + IntersectsPoint = anglesnappedPoint.current; + } + if (visibleIntersect.object instanceof THREE.Mesh) { + const ThroughPoint = visibleIntersect.object.geometry.parameters.path.getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); + let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint); - if (intersectionPoint) { - const newLines = splitLine( - visibleIntersect, - intersectionPoint, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - lines, - setDeletedLines, - floorPlanGroupLine, - socket, - CONSTANTS.pointConfig.wallOuterColor, - CONSTANTS.lineConfig.wallColor, - CONSTANTS.lineConfig.wallName, - projectId, - versionId - ); - setNewLines([newLines[0], newLines[1]]); + if (intersectionPoint) { + const newLines = splitLine( + visibleIntersect, + intersectionPoint, + currentLayerPoint, + floorPlanGroupPoint, + dragPointControls, + isSnappedUUID, + lines, + setDeletedLines, + floorPlanGroupLine, + socket, + CONSTANTS.pointConfig.wallOuterColor, + CONSTANTS.lineConfig.wallColor, + CONSTANTS.lineConfig.wallName, + projectId, + versionId + ); + setNewLines([newLines[0], newLines[1]]); - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); + (line.current as Types.Line).push([ + new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), + isSnappedUUID.current!, + activeLayer, + CONSTANTS.lineConfig.wallName, + ]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); + if (line.current.length >= 2 && line.current[0] && line.current[1]) { + const data = arrayLineToObject(line.current as Types.Line); - //REST + //REST - // setLine(organization, data.layer!, data.line!, data.type!); + // setLine(organization, data.layer!, data.line!, data.type!); - //SOCKET + //SOCKET - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; + const input = { + organization, + layer: data.layer, + line: data.line, + type: data.type, + socketId: socket.id, + versionId, + projectId, + userId, + }; - console.log('input: ', input); - socket.emit("v1:Line:create", input); + socket.emit("v1:Line:create", input); - setNewLines([newLines[0], newLines[1], line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - return; - } - } - } - } + setNewLines([newLines[0], newLines[1], line.current]); + lines.current.push(line.current as Types.Line); + addLineToScene( + line.current[0][0], + line.current[1][0], + CONSTANTS.lineConfig.wallColor, + line.current, + floorPlanGroupLine + ); + let lastPoint = line.current[line.current.length - 1]; + line.current = [lastPoint]; + } + return; + } + } + } + } - if (intersects && intersects.length > 0) { - ////////// Clicked on a emply place or a point ////////// + if (intersects && intersects.length > 0) { + ////////// Clicked on a emply place or a point ////////// - let intersectionPoint = intersects[0].point; + let intersectionPoint = intersects[0].point; - if ( - isAngleSnapped.current && - line.current.length > 0 && - anglesnappedPoint.current - ) { - intersectionPoint = anglesnappedPoint.current; - } - if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } - if (ispreSnapped.current && snappedPoint.current) { - intersectionPoint = snappedPoint.current; - } + if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { + intersectionPoint = anglesnappedPoint.current; + } + if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { + intersectionPoint = snappedPoint.current; + } + if (ispreSnapped.current && snappedPoint.current) { + intersectionPoint = snappedPoint.current; + } - if (!isSnapped.current && !ispreSnapped.current) { - addPointToScene( - intersectionPoint, - CONSTANTS.pointConfig.wallOuterColor, - currentLayerPoint, - floorPlanGroupPoint, - dragPointControls, - isSnappedUUID, - CONSTANTS.lineConfig.wallName - ); - } else { - ispreSnapped.current = false; - isSnapped.current = false; - } + if (!isSnapped.current && !ispreSnapped.current) { + addPointToScene( + intersectionPoint, + CONSTANTS.pointConfig.wallOuterColor, + currentLayerPoint, + floorPlanGroupPoint, + dragPointControls, + isSnappedUUID, + CONSTANTS.lineConfig.wallName + ); + } else { + ispreSnapped.current = false; + isSnapped.current = false; + } - (line.current as Types.Line).push([ - new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), - isSnappedUUID.current!, - activeLayer, - CONSTANTS.lineConfig.wallName, - ]); + (line.current as Types.Line).push([ + new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), + isSnappedUUID.current!, + activeLayer, + CONSTANTS.lineConfig.wallName, + ]); - if (line.current.length >= 2 && line.current[0] && line.current[1]) { - const data = arrayLineToObject(line.current as Types.Line); + if (line.current.length >= 2 && line.current[0] && line.current[1]) { + const data = arrayLineToObject(line.current as Types.Line); - //REST + //REST - // setLine(organization, data.layer!, data.line!, data.type!); + // setLine(organization, data.layer!, data.line!, data.type!); - //SOCKET + //SOCKET - const input = { - organization, - layer: data.layer, - line: data.line, - type: data.type, - socketId: socket.id, - versionId, - projectId, - userId, - }; + const input = { + organization, + layer: data.layer, + line: data.line, + type: data.type, + socketId: socket.id, + versionId, + projectId, + userId, + }; - console.log('input: ', input); - socket.emit("v1:Line:create", input); + socket.emit("v1:Line:create", input); - setNewLines([line.current]); - lines.current.push(line.current as Types.Line); - addLineToScene( - line.current[0][0], - line.current[1][0], - CONSTANTS.lineConfig.wallColor, - line.current, - floorPlanGroupLine - ); - let lastPoint = line.current[line.current.length - 1]; - line.current = [lastPoint]; - } - if (isSnapped.current) { - removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); - } - } + setNewLines([line.current]); + lines.current.push(line.current as Types.Line); + addLineToScene( + line.current[0][0], + line.current[1][0], + CONSTANTS.lineConfig.wallColor, + line.current, + floorPlanGroupLine + ); + let lastPoint = line.current[line.current.length - 1]; + line.current = [lastPoint]; + } + if (isSnapped.current) { + removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); + } + } } export default drawWall; From b4745451d280c5ce2478f8e51f7aa9d8b0cf7473 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 26 Jun 2025 09:51:11 +0530 Subject: [PATCH 7/7] Refactor SidePannel component and update builderTypes to ensure consistent decal property syntax --- app/src/components/Dashboard/SidePannel.tsx | 8 ++------ app/src/types/builderTypes.d.ts | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/src/components/Dashboard/SidePannel.tsx b/app/src/components/Dashboard/SidePannel.tsx index 89b7ba9..5cfaeb0 100644 --- a/app/src/components/Dashboard/SidePannel.tsx +++ b/app/src/components/Dashboard/SidePannel.tsx @@ -42,7 +42,6 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { const projectId = generateProjectId(); useSocketStore.getState().initializeSocket(email, organization, token); - //API for creating new Project // const project = await createProject( // projectId, @@ -50,18 +49,16 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { // savedTheme === "dark" ? darkThemeImage : lightThemeImage, // organization // ); - // console.log('Created project: ', project); + const addProject = { userId, thumbnail: savedTheme === "dark" ? darkThemeImage : lightThemeImage, organization: organization, projectUuid: projectId, }; - // console.log("projectSocket: ", projectSocket); + if (projectSocket) { - // console.log('addProject: ', addProject); const handleResponse = (data: any) => { - // console.log('Project add response:', data); if (data.message === "Project created successfully") { setLoadingProgress(1) navigate(`/${data.data.projectId}`); @@ -70,7 +67,6 @@ const SidePannel: React.FC = ({ setActiveTab, activeTab }) => { }; projectSocket.on("v1-project:response:add", handleResponse); - // console.log('addProject: ', addProject); projectSocket.emit("v1:project:add", addProject); } else { console.error("Socket is not connected."); diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index 17349d7..bbc9b7b 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -103,7 +103,7 @@ interface Wall { insideMaterial: string; wallThickness: number; wallHeight: number; - decals: Decal[] + decals: Decal[]; } type Walls = Wall[]; @@ -119,6 +119,7 @@ interface Floor { floorDepth: number; isBeveled: boolean; bevelStrength: number; + decals: Decal[]; } type Floors = Floor[];