From e1200f52d0eb1ffb0d30595829947c4e8adb905a Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 31 Mar 2025 12:07:25 +0530 Subject: [PATCH 01/11] assets added based on categoryin builder --- app/.env | 3 +- .../components/layout/sidebarLeft/Assets.tsx | 93 ++- .../analysis/RenderAnalysisInputs.tsx | 9 +- .../properties/AssetProperties.tsx | 17 +- .../properties/GlobalProperties.tsx | 21 +- app/src/components/ui/Tools.tsx | 76 ++- app/src/components/ui/inputs/InputRange.tsx | 7 +- .../scene/postProcessing/postProcessing.tsx | 228 ++++---- .../assest/assets/getCategoryAsset.ts | 23 + app/src/types/world/worldConstants.ts | 544 +++++++++--------- 10 files changed, 543 insertions(+), 478 deletions(-) create mode 100644 app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts diff --git a/app/.env b/app/.env index 153338d..ff2cfb0 100644 --- a/app/.env +++ b/app/.env @@ -8,7 +8,8 @@ REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 # Base URL for the server marketplace API. -REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 +# REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 +REACT_APP_SERVER_MARKETPLACE_URL=192.168.0.111:3501 # base url for IoT socket server REACT_APP_IOT_SOCKET_SERVER_URL =185.100.212.76:5010 diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 01b8c8e..5cd32f1 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -1,13 +1,29 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import Search from "../../ui/inputs/Search"; import vehicle from "../../../assets/image/vehicles.png"; import workStation from "../../../assets/image/workStation.png"; import machines from "../../../assets/image/machines.png"; import feneration from "../../../assets/image/feneration.png"; import worker from "../../../assets/image/worker.png"; +import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset"; + +interface AssetProp { + filename: string; + thumbnail: string; + category: string; + description: string; + tags: string; + url: String; + uploadDate: number; + isArchieve: boolean; + animated: boolean; + price: number; + CreatedBy: String; +} const Assets: React.FC = () => { const [searchValue, setSearchValue] = useState(""); const [selectedCategory, setSelectedCategory] = useState(null); + const [filteredAsset, setFilteredAsset] = useState([]); const handleSearchChange = (value: string) => { setSearchValue(value); @@ -34,56 +50,18 @@ const Assets: React.FC = () => { categoryImage: feneration, }, { - assetName: "Forklift", - assetImage: "", category: "Vehicles", categoryImage: vehicle, }, { - assetName: "AGV", - assetImage: "", - category: "Vehicles", - categoryImage: vehicle, - }, - { - assetName: "Pallet", - assetImage: "", category: "Workstation", categoryImage: workStation, }, { - assetName: "Controller", - assetImage: "", - category: "Workstation", - categoryImage: workStation, - }, - { - assetName: "Conveyor", - assetImage: "", - category: "Workstation", - categoryImage: workStation, - }, - { - assetName: "VMC", - assetImage: "", category: "Machines", categoryImage: machines, }, { - assetName: "CMC", - assetImage: "", - category: "Machines", - categoryImage: machines, - }, - { - assetName: "Male Worker", - assetImage: "", - category: "Workers", - categoryImage: worker, - }, - { - assetName: "Female Worker", - assetImage: "", category: "Workers", categoryImage: worker, }, @@ -94,12 +72,13 @@ const Assets: React.FC = () => { new Set(categoryList.map((asset) => asset.category)) ); - // Filter assets based on the selected category - const filteredAssets = - selectedCategory !== null - ? categoryList.filter((asset) => asset.category === selectedCategory) - : []; - + const fetchCategoryAssets = async (asset: any) => { + try { + setSelectedCategory(asset); + const res = await getCategoryAsset(asset); + setFilteredAsset(res); + } catch (error) {} + }; return (
@@ -118,16 +97,17 @@ const Assets: React.FC = () => {

{selectedCategory}

- {filteredAssets.map((asset, index) => ( -
- {asset.assetName} -
{asset.assetName}
-
- ))} + {filteredAsset && + filteredAsset?.map((asset: any, index: number) => ( +
+ {asset.filename} +
{asset.filename}
+
+ ))}
) : ( @@ -142,7 +122,7 @@ const Assets: React.FC = () => {
setSelectedCategory(category)} + onClick={() => fetchCategoryAssets(category)} > { }; export default Assets; - diff --git a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx index aea58eb..3ab886f 100644 --- a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx +++ b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx @@ -27,7 +27,14 @@ const RenderAnalysisInputs: React.FC = ({ ); } if (preset.type === "range") { - return ; + return ( + + ); } return null; })} diff --git a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx index c47fd81..474ee71 100644 --- a/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/AssetProperties.tsx @@ -17,12 +17,6 @@ const AssetProperties: React.FC = () => { const [userData, setUserData] = useState([]); // State to track user data const [nextId, setNextId] = useState(1); // Unique ID for new entries const { selectedFloorItem } = useselectedFloorItem(); - let xValue = selectedFloorItem.position.x; - let zValue = selectedFloorItem.position.z; - let rotationRad = selectedFloorItem.rotation.y; - let rotationDeg = THREE.MathUtils.radToDeg(rotationRad); - - // useEffect(() => {}, [selectedFloorItem]); // Function to handle adding new user data const handleAddUserData = () => { const newUserData: UserData = { @@ -59,10 +53,15 @@ const AssetProperties: React.FC = () => { {}} - value1={xValue.toFixed(5)} - value2={zValue.toFixed(5)} + value1={selectedFloorItem.position.x.toFixed(5)} + value2={selectedFloorItem.position.z.toFixed(5)} + /> + {}} + value={parseFloat( + THREE.MathUtils.radToDeg(selectedFloorItem.rotation.y).toFixed(5) + )} /> - {}} value={rotationDeg} />
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 633b144..bd7e5c1 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -16,7 +16,7 @@ import { useWallVisibility, } from "../../../../store/store"; import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment"; - +import * as CONSTANTS from "../../../../types/world/worldConstants"; const GlobalProperties: React.FC = () => { const { toggleView, setToggleView } = useToggleView(); const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); @@ -29,18 +29,20 @@ const GlobalProperties: React.FC = () => { const { renderDistance, setRenderDistance } = useRenderDistance(); const { socket } = useSocketStore(); const [limitDistance, setLimitDistance] = useState(false); - const [distance, setDistance] = useState(5); + const [distance, setDistance] = useState(30); const [limitGridDistance, setLimitGridDistance] = useState(false); const [gridDistance, setGridDistance] = useState(5); function optimizeScene() { setLimitDistance(true); - setDistance(5); + setDistance(30); } function updateDistance(value: number) { + console.log("value: ", value); setDistance(value); + setRenderDistance(value); } function updateGridDistance(value: number) { @@ -134,6 +136,15 @@ const GlobalProperties: React.FC = () => { } }; + // function changeRenderDistance(e: any) { + // if (parseInt(e.target.value) < 20) { + // setRenderDistance(20); + // } else if (parseInt(e.target.value) > 75) { + // setRenderDistance(75); + // } else { + // setRenderDistance(parseInt(e.target.value)); + // } + // } return (
Environment
@@ -169,7 +180,7 @@ const GlobalProperties: React.FC = () => { />
- + {/* //visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor} */} { disabled={!limitDistance} value={distance} key={"5"} + min={CONSTANTS.distanceConfig.minDistance} + max={CONSTANTS.distanceConfig.maxDistance} onChange={(value: number) => updateDistance(value)} /> diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index c86164c..89f1553 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -62,9 +62,15 @@ const Tools: React.FC = () => { // Reset activeTool whenever activeModule changes useEffect(() => { - setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true) + setToggleUI( + localStorage.getItem("navBarUi") + ? localStorage.getItem("navBarUi") === "true" + : true + ); }, []); - + useEffect(() => { + console.log("activeModule", activeModule); + }, [activeModule]); useEffect(() => { setActiveTool(activeSubTool); setActiveSubTool(activeSubTool); @@ -80,7 +86,11 @@ const Tools: React.FC = () => { } else { setToggleView(false); } - setToggleUI(localStorage.getItem('navBarUi') ? localStorage.getItem('navBarUi') === 'true' : true) + setToggleUI( + localStorage.getItem("navBarUi") + ? localStorage.getItem("navBarUi") === "true" + : true + ); setToggleThreeD(!toggleThreeD); setActiveSubTool("cursor"); setActiveTool("cursor"); @@ -202,8 +212,9 @@ const Tools: React.FC = () => {
{activeSubTool == "cursor" && (
{ setActiveTool("cursor"); }} @@ -213,8 +224,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "free-hand" && (
{ setActiveTool("free-hand"); }} @@ -224,8 +236,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "delete" && (
{ setActiveTool("delete"); }} @@ -297,8 +310,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-wall"); }} @@ -307,8 +321,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-zone"); }} @@ -317,8 +332,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-aisle"); }} @@ -327,8 +343,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-floor"); }} @@ -344,8 +361,9 @@ const Tools: React.FC = () => {
{ setActiveTool("measure"); }} @@ -361,8 +379,9 @@ const Tools: React.FC = () => {
{ setActiveTool("pen"); }} @@ -394,8 +413,9 @@ const Tools: React.FC = () => {
{ setActiveTool("comment"); }} @@ -404,8 +424,9 @@ const Tools: React.FC = () => {
{toggleThreeD && (
{ setIsPlaying(!isPlaying); }} @@ -416,8 +437,9 @@ const Tools: React.FC = () => {
diff --git a/app/src/components/ui/inputs/InputRange.tsx b/app/src/components/ui/inputs/InputRange.tsx index b46d9b4..a09a782 100644 --- a/app/src/components/ui/inputs/InputRange.tsx +++ b/app/src/components/ui/inputs/InputRange.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; - +import * as CONSTANTS from "../../../types/world/worldConstants"; interface InputToggleProps { label: string; // Represents the toggle state (on/off) min?: number; @@ -14,8 +14,8 @@ const InputRange: React.FC = ({ label, onClick, onChange, - min = 0, - max = 10, + min, + max, disabled, value = 5, }) => { @@ -23,6 +23,7 @@ const InputRange: React.FC = ({ function handleChange(e: React.ChangeEvent) { const newValue = parseInt(e.target.value); // Parse the value to an integer + setRangeValue(newValue); // Update the local state if (onChange) { diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index e1fc501..15597b8 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -1,111 +1,125 @@ -import * as THREE from 'three' -import { EffectComposer, N8AO, Outline } from '@react-three/postprocessing' -import { BlendFunction } from 'postprocessing' -import { useDeletableFloorItem, useSelectedActionSphere, useSelectedPath, useSelectedWallItem, useselectedFloorItem } from '../../../store/store'; -import * as Types from '../../../types/world/worldTypes' -import * as CONSTANTS from '../../../types/world/worldConstants'; +import * as THREE from "three"; +import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing"; +import { BlendFunction } from "postprocessing"; +import { + useDeletableFloorItem, + useSelectedActionSphere, + useSelectedPath, + useSelectedWallItem, + useselectedFloorItem, +} from "../../../store/store"; +import * as Types from "../../../types/world/worldTypes"; +import * as CONSTANTS from "../../../types/world/worldConstants"; +import { useEffect } from "react"; export default function PostProcessing() { - const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); - const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); - const { selectedFloorItem, setselectedFloorItem } = useselectedFloorItem(); - const { selectedActionSphere } = useSelectedActionSphere(); - const { selectedPath } = useSelectedPath(); + const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); + const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); + const { selectedFloorItem, setselectedFloorItem } = useselectedFloorItem(); + const { selectedActionSphere } = useSelectedActionSphere(); + const { selectedPath } = useSelectedPath(); - function flattenChildren(children: any[]) { - const allChildren: any[] = []; - children.forEach(child => { - allChildren.push(child); - if (child.children && child.children.length > 0) { - allChildren.push(...flattenChildren(child.children)); - } - }); - return allChildren; - } + function flattenChildren(children: any[]) { + const allChildren: any[] = []; + children.forEach((child) => { + allChildren.push(child); + if (child.children && child.children.length > 0) { + allChildren.push(...flattenChildren(child.children)); + } + }); + return allChildren; + } - return ( - <> - - - {deletableFloorItem && - - } - {selectedWallItem && - child.name !== "CSG_REF" - ) - } - selectionLayer={10} - width={3000} - blendFunction={BlendFunction.ALPHA} - edgeStrength={5} - resolutionScale={2} - pulseSpeed={0} - visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} - blur={true} - xRay={true} - />} - {selectedFloorItem && - - } - {selectedActionSphere && - - } - {selectedPath && - - } - - - ) -} \ No newline at end of file + return ( + <> + + + {deletableFloorItem && ( + + )} + {selectedWallItem && ( + child.name !== "CSG_REF" + )} + selectionLayer={10} + width={3000} + blendFunction={BlendFunction.ALPHA} + edgeStrength={5} + resolutionScale={2} + pulseSpeed={0} + visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor} + blur={true} + xRay={true} + /> + )} + {selectedFloorItem && ( + + )} + {selectedActionSphere && ( + + )} + {selectedPath && ( + + )} + + + ); +} diff --git a/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts b/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts new file mode 100644 index 0000000..9620fce --- /dev/null +++ b/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts @@ -0,0 +1,23 @@ +let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; +export const getCategoryAsset = async (categoryName: any) => { + console.log("categoryName:api ", categoryName); + try { + const response = await fetch( + `${BackEnd_url}/api/v2/getCatagoryAssets/${categoryName}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + // body: JSON.stringify({ filename }), + } + ); + + const result = await response.json(); + console.log("result: ", result); + return result; + } catch (error: any) { + // console.error("Error fetching category:", error.message); + throw new Error(error.message); + } +}; diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index b14e799..66743fb 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -1,384 +1,390 @@ export type Controls = { - azimuthRotateSpeed: number; - polarRotateSpeed: number; - truckSpeed: number; - minDistance: number; - maxDistance: number; - maxPolarAngle: number; - leftMouse: number; - forwardSpeed: number; - backwardSpeed: number; - leftSpeed: number; - rightSpeed: number; + azimuthRotateSpeed: number; + polarRotateSpeed: number; + truckSpeed: number; + minDistance: number; + maxDistance: number; + maxPolarAngle: number; + leftMouse: number; + forwardSpeed: number; + backwardSpeed: number; + leftSpeed: number; + rightSpeed: number; }; export type ThirdPersonControls = { - azimuthRotateSpeed: number; - polarRotateSpeed: number; - truckSpeed: number; - maxDistance: number; - maxPolarAngle: number; - minZoom: number; - maxZoom: number; - targetOffset: number; - cameraHeight: number; - leftMouse: number; - rightMouse: number; - wheelMouse: number; - middleMouse: number; + azimuthRotateSpeed: number; + polarRotateSpeed: number; + truckSpeed: number; + maxDistance: number; + maxPolarAngle: number; + minZoom: number; + maxZoom: number; + targetOffset: number; + cameraHeight: number; + leftMouse: number; + rightMouse: number; + wheelMouse: number; + middleMouse: number; }; export type ControlsTransition = { - leftMouse: number; - rightMouse: number; - wheelMouse: number; - middleMouse: number; + leftMouse: number; + rightMouse: number; + wheelMouse: number; + middleMouse: number; }; export type TwoDimension = { - defaultPosition: [x: number, y: number, z: number]; - defaultTarget: [x: number, y: number, z: number]; - defaultAzimuth: number; - minDistance: number; - leftMouse: number; - rightMouse: number; + defaultPosition: [x: number, y: number, z: number]; + defaultTarget: [x: number, y: number, z: number]; + defaultAzimuth: number; + minDistance: number; + leftMouse: number; + rightMouse: number; }; export type ThreeDimension = { - defaultPosition: [x: number, y: number, z: number]; - defaultTarget: [x: number, y: number, z: number]; - defaultRotation: [x: number, y: number, z: number]; - defaultAzimuth: number; - boundaryBottom: [x: number, y: number, z: number]; - boundaryTop: [x: number, y: number, z: number]; - minDistance: number; - leftMouse: number; - rightMouse: number; + defaultPosition: [x: number, y: number, z: number]; + defaultTarget: [x: number, y: number, z: number]; + defaultRotation: [x: number, y: number, z: number]; + defaultAzimuth: number; + boundaryBottom: [x: number, y: number, z: number]; + boundaryTop: [x: number, y: number, z: number]; + minDistance: number; + leftMouse: number; + rightMouse: number; }; - export type GridConfig = { - size: number; - divisions: number; - primaryColor: string; - secondaryColor: string; + size: number; + divisions: number; + primaryColor: string; + secondaryColor: string; - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; -} + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; +}; export type PlaneConfig = { - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; - rotation: number; + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; + rotation: number; - width: number; - height: number; - color: string; -} + width: number; + height: number; + color: string; +}; export type ShadowConfig = { - shadowOffset: number, + shadowOffset: number; - shadowmapSizewidth: number, - shadowmapSizeheight: number, - shadowcamerafar: number, - shadowcameranear: number, - shadowcameratop: number, - shadowcamerabottom: number, - shadowcameraleft: number, - shadowcameraright: number, - shadowbias: number, - shadownormalBias: number, + shadowmapSizewidth: number; + shadowmapSizeheight: number; + shadowcamerafar: number; + shadowcameranear: number; + shadowcameratop: number; + shadowcamerabottom: number; + shadowcameraleft: number; + shadowcameraright: number; + shadowbias: number; + shadownormalBias: number; - shadowMaterialPosition: [x: number, y: number, z: number], - shadowMaterialRotation: [x: number, y: number, z: number], + shadowMaterialPosition: [x: number, y: number, z: number]; + shadowMaterialRotation: [x: number, y: number, z: number]; - shadowMaterialOpacity: number, -} + shadowMaterialOpacity: number; +}; export type SkyConfig = { - defaultTurbidity: number; - maxTurbidity: number; - minTurbidity: number; - defaultRayleigh: number; - mieCoefficient: number; - mieDirectionalG: number; - skyDistance: number; -} + defaultTurbidity: number; + maxTurbidity: number; + minTurbidity: number; + defaultRayleigh: number; + mieCoefficient: number; + mieDirectionalG: number; + skyDistance: number; +}; export type AssetConfig = { - defaultScaleBeforeGsap: [number, number, number]; - defaultScaleAfterGsap: [number, number, number]; -} + defaultScaleBeforeGsap: [number, number, number]; + defaultScaleAfterGsap: [number, number, number]; +}; export type PointConfig = { - defaultInnerColor: string; - defaultOuterColor: string; - deleteColor: string; - boxScale: [number, number, number]; + defaultInnerColor: string; + defaultOuterColor: string; + deleteColor: string; + boxScale: [number, number, number]; - wallOuterColor: string; - floorOuterColor: string; - aisleOuterColor: string; - zoneOuterColor: string; + wallOuterColor: string; + floorOuterColor: string; + aisleOuterColor: string; + zoneOuterColor: string; - snappingThreshold: number; -} + snappingThreshold: number; +}; export type LineConfig = { - tubularSegments: number; - radius: number; - radialSegments: number; + tubularSegments: number; + radius: number; + radialSegments: number; - wallName: string; - floorName: string; - aisleName: string; - zoneName: string; - referenceName: string; + wallName: string; + floorName: string; + aisleName: string; + zoneName: string; + referenceName: string; - lineIntersectionPoints: number; + lineIntersectionPoints: number; - defaultColor: string; + defaultColor: string; - wallColor: string; - floorColor: string; - aisleColor: string; - zoneColor: string; - helperColor: string; -} + wallColor: string; + floorColor: string; + aisleColor: string; + zoneColor: string; + helperColor: string; +}; export type WallConfig = { - defaultColor: string; - height: number; - width: number; -} + defaultColor: string; + height: number; + width: number; +}; export type FloorConfig = { - defaultColor: string; - height: number; + defaultColor: string; + height: number; - textureScale: number; -} + textureScale: number; +}; export type RoofConfig = { - defaultColor: string; - height: number; -} + defaultColor: string; + height: number; +}; export type AisleConfig = { - width: number; - height: number; + width: number; + height: number; - defaultColor: number; -} + defaultColor: number; +}; export type ZoneConfig = { - defaultColor: string; + defaultColor: string; - color: string; -} + color: string; +}; export type ColumnConfig = { - defaultColor: string; -} + defaultColor: string; +}; export type OutlineConfig = { - assetSelectColor: number; - assetDeleteColor: number; -} - - + assetSelectColor: number; + assetDeleteColor: number; +}; +export type DistanceConfig = { + minDistance: number; + maxDistance: number; +}; export const firstPersonControls: Controls = { - azimuthRotateSpeed: 0.3, // Speed of rotation around the azimuth axis - polarRotateSpeed: 0.3, // Speed of rotation around the polar axis - truckSpeed: 10, // Speed of truck movement - minDistance: 0, // Minimum distance from the target - maxDistance: 0, // Maximum distance from the target - maxPolarAngle: Math.PI, // Maximum polar angle + azimuthRotateSpeed: 0.3, // Speed of rotation around the azimuth axis + polarRotateSpeed: 0.3, // Speed of rotation around the polar axis + truckSpeed: 10, // Speed of truck movement + minDistance: 0, // Minimum distance from the target + maxDistance: 0, // Maximum distance from the target + maxPolarAngle: Math.PI, // Maximum polar angle - leftMouse: 1, // Mouse button for rotation (ROTATE) + leftMouse: 1, // Mouse button for rotation (ROTATE) - forwardSpeed: 0.3, // Speed of forward movement - backwardSpeed: -0.3, // Speed of backward movement - leftSpeed: -0.3, // Speed of left movement - rightSpeed: 0.3, // Speed of right movement + forwardSpeed: 0.3, // Speed of forward movement + backwardSpeed: -0.3, // Speed of backward movement + leftSpeed: -0.3, // Speed of left movement + rightSpeed: 0.3, // Speed of right movement }; export const thirdPersonControls: ThirdPersonControls = { - azimuthRotateSpeed: 1, // Speed of rotation around the azimuth axis - polarRotateSpeed: 1, // Speed of rotation around the polar axis - truckSpeed: 2, // Speed of truck movement - maxDistance: 100, // Maximum distance from the target - maxPolarAngle: Math.PI / 2 - 0.05, // Maximum polar angle - minZoom: 6, // Minimum zoom level - maxZoom: 21, // Maximum zoom level - targetOffset: 20, // Offset of the target from the camera - cameraHeight: 30, // Height of the camera - leftMouse: 2, // Mouse button for panning - rightMouse: 1, // Mouse button for rotation - wheelMouse: 8, // Mouse button for zooming - middleMouse: 8, // Mouse button for zooming + azimuthRotateSpeed: 1, // Speed of rotation around the azimuth axis + polarRotateSpeed: 1, // Speed of rotation around the polar axis + truckSpeed: 2, // Speed of truck movement + maxDistance: 100, // Maximum distance from the target + maxPolarAngle: Math.PI / 2 - 0.05, // Maximum polar angle + minZoom: 6, // Minimum zoom level + maxZoom: 21, // Maximum zoom level + targetOffset: 20, // Offset of the target from the camera + cameraHeight: 30, // Height of the camera + leftMouse: 2, // Mouse button for panning + rightMouse: 1, // Mouse button for rotation + wheelMouse: 8, // Mouse button for zooming + middleMouse: 8, // Mouse button for zooming }; export const controlsTransition: ControlsTransition = { - leftMouse: 0, // Mouse button for no action - rightMouse: 0, // Mouse button for no action - wheelMouse: 0, // Mouse button for no action - middleMouse: 0, // Mouse button for no action + leftMouse: 0, // Mouse button for no action + rightMouse: 0, // Mouse button for no action + wheelMouse: 0, // Mouse button for no action + middleMouse: 0, // Mouse button for no action }; export const twoDimension: TwoDimension = { - defaultPosition: [0, 100, 0], // Default position of the camera - defaultTarget: [0, 0, 0], // Default target of the camera - defaultAzimuth: 0, // Default azimuth of the camera - minDistance: 25, // Minimum distance from the target - leftMouse: 2, // Mouse button for panning - rightMouse: 0, // Mouse button for no action + defaultPosition: [0, 100, 0], // Default position of the camera + defaultTarget: [0, 0, 0], // Default target of the camera + defaultAzimuth: 0, // Default azimuth of the camera + minDistance: 25, // Minimum distance from the target + leftMouse: 2, // Mouse button for panning + rightMouse: 0, // Mouse button for no action }; export const threeDimension: ThreeDimension = { - defaultPosition: [0, 40, 30], // Default position of the camera - defaultTarget: [0, 0, 0], // Default target of the camera - defaultRotation: [0, 0, 0], // Default rotation of the camera - defaultAzimuth: 0, // Default azimuth of the camera - boundaryBottom: [-150, 0, -150], // Bottom boundary of the camera movement - boundaryTop: [150, 100, 150], // Top boundary of the camera movement - minDistance: 1, // Minimum distance from the target - leftMouse: 2, // Mouse button for panning - rightMouse: 1, // Mouse button for rotation + defaultPosition: [0, 40, 30], // Default position of the camera + defaultTarget: [0, 0, 0], // Default target of the camera + defaultRotation: [0, 0, 0], // Default rotation of the camera + defaultAzimuth: 0, // Default azimuth of the camera + boundaryBottom: [-150, 0, -150], // Bottom boundary of the camera movement + boundaryTop: [150, 100, 150], // Top boundary of the camera movement + minDistance: 1, // Minimum distance from the target + leftMouse: 2, // Mouse button for panning + rightMouse: 1, // Mouse button for rotation }; export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position export const gridConfig: GridConfig = { - size: 300, // Size of the grid - divisions: 75, // Number of divisions in the grid - primaryColor: "#d5d5d5", // Primary color of the grid - secondaryColor: "#e3e3e3", // Secondary color of the grid + size: 300, // Size of the grid + divisions: 75, // Number of divisions in the grid + primaryColor: "#d5d5d5", // Primary color of the grid + secondaryColor: "#e3e3e3", // Secondary color of the grid - position2D: [0, 0.1, 0], // Position of the grid in 2D view - position3D: [0, -0.5, 0], // Position of the grid in 3D view -} + position2D: [0, 0.1, 0], // Position of the grid in 2D view + position3D: [0, -0.5, 0], // Position of the grid in 3D view +}; export const planeConfig: PlaneConfig = { - position2D: [0, -0.5, 0], // Position of the plane - position3D: [0, -0.65, 0], // Position of the plane - rotation: -Math.PI / 2, // Rotation of the plane + position2D: [0, -0.5, 0], // Position of the plane + position3D: [0, -0.65, 0], // Position of the plane + rotation: -Math.PI / 2, // Rotation of the plane - width: 300, // Width of the plane - height: 300, // Height of the plane - color: "#f3f3f3" // Color of the plane -} + width: 300, // Width of the plane + height: 300, // Height of the plane + color: "#f3f3f3", // Color of the plane +}; export const shadowConfig: ShadowConfig = { - shadowOffset: 50, // Offset of the shadow + shadowOffset: 50, // Offset of the shadow - shadowmapSizewidth: 1024, // Width of the shadow map - shadowmapSizeheight: 1024, // Height of the shadow map - // shadowmapSizewidth: 8192, // Width of the shadow map - // shadowmapSizeheight: 8192, // Height of the shadow map - shadowcamerafar: 70, // Far plane of the shadow camera - shadowcameranear: 0.1, // Near plane of the shadow camera - shadowcameratop: 30, // Top plane of the shadow camera - shadowcamerabottom: -30, // Bottom plane of the shadow camera - shadowcameraleft: -30, // Left plane of the shadow camera - shadowcameraright: 30, // Right plane of the shadow camera - shadowbias: -0.001, // Bias of the shadow - shadownormalBias: 0.02, // Normal bias of the shadow + shadowmapSizewidth: 1024, // Width of the shadow map + shadowmapSizeheight: 1024, // Height of the shadow map + // shadowmapSizewidth: 8192, // Width of the shadow map + // shadowmapSizeheight: 8192, // Height of the shadow map + shadowcamerafar: 70, // Far plane of the shadow camera + shadowcameranear: 0.1, // Near plane of the shadow camera + shadowcameratop: 30, // Top plane of the shadow camera + shadowcamerabottom: -30, // Bottom plane of the shadow camera + shadowcameraleft: -30, // Left plane of the shadow camera + shadowcameraright: 30, // Right plane of the shadow camera + shadowbias: -0.001, // Bias of the shadow + shadownormalBias: 0.02, // Normal bias of the shadow - shadowMaterialPosition: [0, 0.01, 0], // Position of the shadow material - shadowMaterialRotation: [-Math.PI / 2, 0, 0], // Rotation of the shadow material + shadowMaterialPosition: [0, 0.01, 0], // Position of the shadow material + shadowMaterialRotation: [-Math.PI / 2, 0, 0], // Rotation of the shadow material - shadowMaterialOpacity: 0.1 // Opacity of the shadow material -} + shadowMaterialOpacity: 0.1, // Opacity of the shadow material +}; export const skyConfig: SkyConfig = { - defaultTurbidity: 10.0, // Default turbidity of the sky - maxTurbidity: 20.0, // Maximum turbidity of the sky - minTurbidity: 0.0, // Minimum turbidity of the sky - defaultRayleigh: 1.9, // Default Rayleigh scattering coefficient - mieCoefficient: 0.1, // Mie scattering coefficient - mieDirectionalG: 1.0, // Mie directional G - skyDistance: 2000 // Distance of the sky -} + defaultTurbidity: 10.0, // Default turbidity of the sky + maxTurbidity: 20.0, // Maximum turbidity of the sky + minTurbidity: 0.0, // Minimum turbidity of the sky + defaultRayleigh: 1.9, // Default Rayleigh scattering coefficient + mieCoefficient: 0.1, // Mie scattering coefficient + mieDirectionalG: 1.0, // Mie directional G + skyDistance: 2000, // Distance of the sky +}; export const assetConfig: AssetConfig = { - defaultScaleBeforeGsap: [0.1, 0.1, 0.1], // Default scale of the assets - defaultScaleAfterGsap: [1, 1, 1] // Default scale of the assets -} + defaultScaleBeforeGsap: [0.1, 0.1, 0.1], // Default scale of the assets + defaultScaleAfterGsap: [1, 1, 1], // Default scale of the assets +}; export const pointConfig: PointConfig = { - defaultInnerColor: "#ffffff", // Default inner color of the points - defaultOuterColor: "#ffffff", // Default outer color of the points - deleteColor: "#ff0000", // Color of the points when deleting - boxScale: [0.5, 0.5, 0.5], // Scale of the points + defaultInnerColor: "#ffffff", // Default inner color of the points + defaultOuterColor: "#ffffff", // Default outer color of the points + deleteColor: "#ff0000", // Color of the points when deleting + boxScale: [0.5, 0.5, 0.5], // Scale of the points - wallOuterColor: "#C7C7C7", // Outer color of the wall points - floorOuterColor: "#808080", // Outer color of the floor points - aisleOuterColor: "#FBBC05", // Outer color of the aisle points - zoneOuterColor: "#007BFF", // Outer color of the zone points + wallOuterColor: "#C7C7C7", // Outer color of the wall points + floorOuterColor: "#808080", // Outer color of the floor points + aisleOuterColor: "#FBBC05", // Outer color of the aisle points + zoneOuterColor: "#007BFF", // Outer color of the zone points - snappingThreshold: 1, // Threshold for snapping -} + snappingThreshold: 1, // Threshold for snapping +}; export const lineConfig: LineConfig = { - tubularSegments: 64, // Number of tubular segments - radius: 0.15, // Radius of the lines - radialSegments: 8, // Number of radial segments + tubularSegments: 64, // Number of tubular segments + radius: 0.15, // Radius of the lines + radialSegments: 8, // Number of radial segments - wallName: "WallLine", // Name of the wall lines - floorName: "FloorLine", // Name of the floor lines - aisleName: "AisleLine", // Name of the aisle lines - zoneName: "ZoneLine", // Name of the zone lines - referenceName: "ReferenceLine", // Name of the reference lines + wallName: "WallLine", // Name of the wall lines + floorName: "FloorLine", // Name of the floor lines + aisleName: "AisleLine", // Name of the aisle lines + zoneName: "ZoneLine", // Name of the zone lines + referenceName: "ReferenceLine", // Name of the reference lines - lineIntersectionPoints: 300, // Number of intersection points + lineIntersectionPoints: 300, // Number of intersection points - defaultColor: "#000000", // Default color of the lines + defaultColor: "#000000", // Default color of the lines - wallColor: "#C7C7C7", // Color of the wall lines - floorColor: "#808080", // Color of the floor lines - aisleColor: "#FBBC05", // Color of the aisle lines - zoneColor: "#007BFF", // Color of the zone lines - helperColor: "#C164FF" // Color of the helper lines -} + wallColor: "#C7C7C7", // Color of the wall lines + floorColor: "#808080", // Color of the floor lines + aisleColor: "#FBBC05", // Color of the aisle lines + zoneColor: "#007BFF", // Color of the zone lines + helperColor: "#C164FF", // Color of the helper lines +}; export const wallConfig: WallConfig = { - defaultColor: "white", // Default color of the walls - height: 7, // Height of the walls - width: 0.05, // Width of the walls -} + defaultColor: "white", // Default color of the walls + height: 7, // Height of the walls + width: 0.05, // Width of the walls +}; export const floorConfig: FloorConfig = { - defaultColor: "grey", // Default color of the floors - height: 0.1, // Height of the floors - textureScale: 0.1, // Scale of the floor texture -} + defaultColor: "grey", // Default color of the floors + height: 0.1, // Height of the floors + textureScale: 0.1, // Scale of the floor texture +}; export const roofConfig: RoofConfig = { - defaultColor: "grey", // Default color of the roofs - height: 0.1 // Height of the roofs -} + defaultColor: "grey", // Default color of the roofs + height: 0.1, // Height of the roofs +}; export const aisleConfig: AisleConfig = { - width: 0.1, // Width of the aisles - height: 0.01, // Height of the aisles - defaultColor: 0xffff00 // Default color of the aisles -} + width: 0.1, // Width of the aisles + height: 0.01, // Height of the aisles + defaultColor: 0xffff00, // Default color of the aisles +}; export const zoneConfig: ZoneConfig = { - defaultColor: "black", // Default color of the zones - color: "blue" // Color of the zones -} + defaultColor: "black", // Default color of the zones + color: "blue", // Color of the zones +}; export const columnConfig: ColumnConfig = { - defaultColor: "White", // Default color of the columns -} + defaultColor: "White", // Default color of the columns +}; export const outlineConfig: OutlineConfig = { - assetSelectColor: 0x0054fE, // Color of the selected assets - assetDeleteColor: 0xFF0000 // Color of the deleted assets -} \ No newline at end of file + assetSelectColor: 0x0054fe, // Color of the selected assets + assetDeleteColor: 0xff0000, // Color of the deleted assets +}; + +export const distanceConfig: DistanceConfig = { + minDistance: 20, + maxDistance: 75, +}; From cacb23ea5a2533a314467f9d06453a10a24569d0 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Mon, 31 Mar 2025 12:59:12 +0530 Subject: [PATCH 02/11] added feneration assets --- .../components/layout/sidebarLeft/Assets.tsx | 149 ++++++++++-------- app/src/components/ui/Tools.tsx | 4 +- app/src/modules/market/AssetPreview.tsx | 2 +- app/src/modules/market/CardsContainer.tsx | 3 +- app/src/modules/market/FilterSearch.tsx | 1 + app/src/modules/market/MarketPlace.tsx | 2 + .../assest/assets/getCategoryAsset.ts | 4 - app/src/styles/layout/sidebar.scss | 10 +- 8 files changed, 100 insertions(+), 75 deletions(-) diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 5cd32f1..f8733dc 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import Search from "../../ui/inputs/Search"; import vehicle from "../../../assets/image/vehicles.png"; import workStation from "../../../assets/image/workStation.png"; @@ -6,19 +6,21 @@ import machines from "../../../assets/image/machines.png"; import feneration from "../../../assets/image/feneration.png"; import worker from "../../../assets/image/worker.png"; import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets/getCategoryAsset"; - +import arch from "../../../assets/gltf-glb/arch.glb"; +import door from "../../../assets/gltf-glb/door.glb"; +import window from "../../../assets/gltf-glb/window.glb"; interface AssetProp { filename: string; - thumbnail: string; + thumbnail?: string; category: string; - description: string; - tags: string; - url: String; - uploadDate: number; - isArchieve: boolean; - animated: boolean; - price: number; - CreatedBy: String; + description?: string; + tags?: string; + url?: String; + uploadDate?: number; + isArchieve?: boolean; + animated?: boolean; + price?: number; + CreatedBy?: String; } const Assets: React.FC = () => { const [searchValue, setSearchValue] = useState(""); @@ -30,55 +32,64 @@ const Assets: React.FC = () => { setSelectedCategory(null); // Reset selected category when search changes }; - const categoryList = [ - { - assetName: "Doors", - assetImage: "", - category: "Feneration", - categoryImage: feneration, - }, - { - assetName: "Windows", - assetImage: "", - category: "Feneration", - categoryImage: feneration, - }, - { - assetName: "Pillars", - assetImage: "", - category: "Feneration", - categoryImage: feneration, - }, - { - category: "Vehicles", - categoryImage: vehicle, - }, - { - category: "Workstation", - categoryImage: workStation, - }, - { - category: "Machines", - categoryImage: machines, - }, - { - category: "Workers", - categoryImage: worker, - }, - ]; - - // Get unique categories - const uniqueCategories = Array.from( - new Set(categoryList.map((asset) => asset.category)) + const categoryList = useMemo( + () => [ + { + assetName: "Doors", + assetImage: "", + category: "Feneration", + categoryImage: feneration, + }, + { + assetName: "Windows", + assetImage: "", + category: "Feneration", + categoryImage: feneration, + }, + { + assetName: "Pillars", + assetImage: "", + category: "Feneration", + categoryImage: feneration, + }, + { category: "Vehicles", categoryImage: vehicle }, + { category: "Workstation", categoryImage: workStation }, + { category: "Machines", categoryImage: machines }, + { category: "Workers", categoryImage: worker }, + ], + [] ); const fetchCategoryAssets = async (asset: any) => { - try { - setSelectedCategory(asset); - const res = await getCategoryAsset(asset); - setFilteredAsset(res); - } catch (error) {} + setSelectedCategory(asset); + if (asset === "Feneration") { + const localAssets: AssetProp[] = [ + { + filename: "arch", + category: "Feneration", + url: arch, + }, + { + filename: "door", + category: "Feneration", + url: door, + }, + { + filename: "window", + category: "Feneration", + url: window, + }, + ]; + setFilteredAsset(localAssets); + } else { + try { + const res = await getCategoryAsset(asset); + setFilteredAsset(res || []); // Ensure it's always an array + } catch (error) {} + } }; + + useEffect(() => {}, [filteredAsset]); return (
@@ -100,12 +111,22 @@ const Assets: React.FC = () => { {filteredAsset && filteredAsset?.map((asset: any, index: number) => (
- {asset.filename} -
{asset.filename}
+ {asset?.thumbnail && ( + {asset.filename} + )} +
+ {asset.filename + .split("_") + .map( + (word: any) => + word.charAt(0).toUpperCase() + word.slice(1) + ) + .join(" ")} +
))}
@@ -114,7 +135,9 @@ const Assets: React.FC = () => {

Categories

- {uniqueCategories.map((category, index) => { + {Array.from( + new Set(categoryList.map((asset) => asset.category)) + ).map((category, index) => { const categoryInfo = categoryList.find( (asset) => asset.category === category ); diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 89f1553..9e7dd1b 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -68,9 +68,7 @@ const Tools: React.FC = () => { : true ); }, []); - useEffect(() => { - console.log("activeModule", activeModule); - }, [activeModule]); + useEffect(() => {}, [activeModule]); useEffect(() => { setActiveTool(activeSubTool); setActiveSubTool(activeSubTool); diff --git a/app/src/modules/market/AssetPreview.tsx b/app/src/modules/market/AssetPreview.tsx index 854ebc4..1d39920 100644 --- a/app/src/modules/market/AssetPreview.tsx +++ b/app/src/modules/market/AssetPreview.tsx @@ -94,7 +94,7 @@ const AssetPreview: React.FC = ({
{selectedCard.assetName}
- {`${selectedCard.assetName} is used in factories to improve efficiency and production speed It is designed to handle heavy workloads and perform repetitive tasks with precision. Many industries rely on this machine to manufacture products quickly and accurately. It reduces human effort and minimizes errors in the production process. Regular maintenance is required to keep the machine in good working condition.With advanced technology, this machine continues to enhance industrial operations and increase productivity.`} + {`${selectedCard.description}`}
diff --git a/app/src/modules/market/CardsContainer.tsx b/app/src/modules/market/CardsContainer.tsx index c2a7e6d..cdbce81 100644 --- a/app/src/modules/market/CardsContainer.tsx +++ b/app/src/modules/market/CardsContainer.tsx @@ -14,6 +14,7 @@ interface ModelData { thumbnail: string; uploadDate: number; _id: string; + price: number; } interface ModelsProps { models: ModelData[]; @@ -50,7 +51,7 @@ const CardsContainer: React.FC = ({ models }) => { key={assetDetail._id} assetName={assetDetail?.filename} uploadedOn={assetDetail.uploadDate} - price={36500} + price={assetDetail?.price} rating={4.5} views={800} onSelectCard={handleCardSelect} diff --git a/app/src/modules/market/FilterSearch.tsx b/app/src/modules/market/FilterSearch.tsx index 84074b8..630942d 100644 --- a/app/src/modules/market/FilterSearch.tsx +++ b/app/src/modules/market/FilterSearch.tsx @@ -17,6 +17,7 @@ interface ModelData { thumbnail: string; uploadDate: number; _id: string; + price: number; } interface ModelsProps { models: ModelData[]; diff --git a/app/src/modules/market/MarketPlace.tsx b/app/src/modules/market/MarketPlace.tsx index d830576..cd2e0e9 100644 --- a/app/src/modules/market/MarketPlace.tsx +++ b/app/src/modules/market/MarketPlace.tsx @@ -15,6 +15,7 @@ interface ModelData { thumbnail: string; uploadDate: number; _id: string; + price: number; } const MarketPlace = () => { const [models, setModels] = useState([]); @@ -24,6 +25,7 @@ const MarketPlace = () => { const filteredAssets = async () => { try { const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6"); + setModels(filt.items); setFilteredModels(filt.items); } catch {} diff --git a/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts b/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts index 9620fce..522e54c 100644 --- a/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts +++ b/app/src/services/factoryBuilder/assest/assets/getCategoryAsset.ts @@ -1,6 +1,5 @@ let BackEnd_url = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; export const getCategoryAsset = async (categoryName: any) => { - console.log("categoryName:api ", categoryName); try { const response = await fetch( `${BackEnd_url}/api/v2/getCatagoryAssets/${categoryName}`, @@ -9,15 +8,12 @@ export const getCategoryAsset = async (categoryName: any) => { headers: { "Content-Type": "application/json", }, - // body: JSON.stringify({ filename }), } ); const result = await response.json(); - console.log("result: ", result); return result; } catch (error: any) { - // console.error("Error fetching category:", error.message); throw new Error(error.message); } }; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 1e2de3c..e8175c5 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -1029,10 +1029,14 @@ } .asset-image { + height: 100%; + width: 100%; position: absolute; - top: 50%; - right: 5px; - transform: translate(0, -50%); + // top: 50%; + // right: 5px; + // transform: translate(0, -50%); + top: 0; + left: 0; z-index: 2; } } From 6e4c8282c5dd1ee2e7dd38034d298e6fd85c6bfb Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 31 Mar 2025 14:28:24 +0530 Subject: [PATCH 03/11] Refactor AssetProperties layout, enhance PositionInput component with optional properties, and implement new asset event fetching logic --- .../customInput/PositionInputs.tsx | 22 +++- .../mechanics/VehicleMechanics.tsx | 72 ++++++++--- .../properties/AssetProperties.tsx | 2 - .../controls/selection/selectionControls.tsx | 36 ++++-- .../simulation/behaviour/behaviour.tsx | 8 +- .../modules/simulation/path/pathConnector.tsx | 115 +++++------------- .../modules/simulation/path/pathCreation.tsx | 102 ++++++++++++++-- app/src/modules/simulation/simulation.tsx | 6 +- .../services/simulation/getAssetEventType.ts | 26 ++++ app/src/store/store.ts | 21 ++++ app/src/types/world/worldTypes.d.ts | 2 +- 11 files changed, 288 insertions(+), 124 deletions(-) create mode 100644 app/src/services/simulation/getAssetEventType.ts diff --git a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx index 881e225..01b4ab3 100644 --- a/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx +++ b/app/src/components/layout/sidebarRight/customInput/PositionInputs.tsx @@ -1,23 +1,32 @@ import React from "react"; +import { EyeDroperIcon } from "../../../icons/ExportCommonIcons"; interface PositionInputProps { + label?: string; // Optional label for the input onChange: (value: string) => void; // Callback for value change placeholder?: string; // Optional placeholder type?: string; // Input type (e.g., text, number, email) value1?: number; value2?: number; + disabled?: boolean; // Optional disabled property + isEyedrop?: boolean; // Optional eyedrop property + handleEyeDropClick?: () => void; // Optional function for eye drop click } const PositionInput: React.FC = ({ onChange, + label = "Position", // Default label placeholder = "Enter value", // Default placeholder type = "number", // Default type value1 = "number", value2 = "number", + disabled = false, // Default disabled value + isEyedrop = false, // Default isEyedrop value + handleEyeDropClick = () => { }, // Default function for eye drop click }) => { return (
-
Position
+
{label}
X :
@@ -26,7 +35,8 @@ const PositionInput: React.FC = ({ type={type} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} - value={value2} + value={value1} + disabled={disabled} // Apply disabled prop />
@@ -36,10 +46,16 @@ const PositionInput: React.FC = ({ type={type} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} - value={value1} + value={value2} + disabled={disabled} // Apply disabled prop />
+ {isEyedrop && ( +
+ +
+ )}
); }; diff --git a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx index c611a13..bf0b112 100644 --- a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx @@ -1,13 +1,16 @@ import React, { useRef, useMemo } from "react"; import { InfoIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store"; +import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationPaths } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; -import LabledDropdown from "../../../ui/inputs/LabledDropdown"; +import PositionInput from "../customInput/PositionInputs"; const VehicleMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); + const { editingPoint, setEditingPoint } = useEditingPoint(); + const { previewPosition, setPreviewPosition } = usePreviewPosition(); const propertiesContainerRef = useRef(null); @@ -59,12 +62,10 @@ const VehicleMechanics: React.FC = () => { setSimulationPaths(updatedPaths); }, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]); - const handleStartPointChange = React.useCallback((uuid: string) => { - handleActionUpdate({ start: uuid }); + const handleStartPointChange = React.useCallback((position: { x: number, y: number }) => { }, [handleActionUpdate]); - const handleEndPointChange = React.useCallback((uuid: string) => { - handleActionUpdate({ end: uuid }); + const handleEndPointChange = React.useCallback((position: { x: number, y: number }) => { }, [handleActionUpdate]); const handleHitCountChange = React.useCallback((hitCount: number) => { @@ -94,6 +95,16 @@ const VehicleMechanics: React.FC = () => { setSimulationPaths(updatedPaths); }, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]); + const handleStartEyeDropClick = () => { + setEditingPoint('start'); + setEyeDropMode(true); + }; + + const handleEndEyeDropClick = () => { + setEditingPoint('end'); + setEyeDropMode(true); + }; + return (
@@ -106,20 +117,49 @@ const VehicleMechanics: React.FC = () => { {selectedPoint && ( <> - { }} + disabled={true} + value1={ + editingPoint === 'start' && previewPosition + ? parseFloat(previewPosition.x.toFixed(4)) + : selectedPoint.actions.start && 'x' in selectedPoint.actions.start + ? parseFloat(selectedPoint.actions.start.x.toFixed(4)) + : 0 + } + value2={ + editingPoint === 'start' && previewPosition + ? parseFloat(previewPosition.y.toFixed(4)) + : selectedPoint.actions.start && 'y' in selectedPoint.actions.start + ? parseFloat(selectedPoint.actions.start.y.toFixed(4)) + : 0 + } + + isEyedrop={true} + handleEyeDropClick={handleStartEyeDropClick} /> - { }} + disabled={true} + value1={ + editingPoint === 'end' && previewPosition + ? parseFloat(previewPosition.x.toFixed(4)) + : selectedPoint.actions.end && 'x' in selectedPoint.actions.end + ? parseFloat(selectedPoint.actions.end.x.toFixed(4)) + : 0 + } + value2={ + editingPoint === 'end' && previewPosition + ? parseFloat(previewPosition.y.toFixed(4)) + : selectedPoint.actions.end && 'y' in selectedPoint.actions.end + ? parseFloat(selectedPoint.actions.end.y.toFixed(4)) + : 0 + } + isEyedrop={true} + handleEyeDropClick={handleEndEyeDropClick} /> { {/* Name */}
{selectedFloorItem.userData.name}
-
- {}} value1={xValue.toFixed(5)} diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selection/selectionControls.tsx index c9038ab..9d5f7ea 100644 --- a/app/src/modules/scene/controls/selection/selectionControls.tsx +++ b/app/src/modules/scene/controls/selection/selectionControls.tsx @@ -42,6 +42,8 @@ const SelectionControls: React.FC = () => { itemsGroupRef.current = itemsGroup; let isSelecting = false; + let isRightClick = false; + let rightClickMoved = false; let isCtrlSelecting = false; const helper = new SelectionHelper(gl); @@ -52,16 +54,23 @@ const SelectionControls: React.FC = () => { } const onPointerDown = (event: PointerEvent) => { - if (event.button !== 0) return - isSelecting = false; - isCtrlSelecting = event.ctrlKey; - if (event.ctrlKey && duplicatedObjects.length === 0) { - if (controls) (controls as any).enabled = false; - selectionBox.startPoint.set(pointer.x, pointer.y, 0); + if (event.button === 2) { + isRightClick = true; + rightClickMoved = false; + } else if (event.button === 0) { + isSelecting = false; + isCtrlSelecting = event.ctrlKey; + if (event.ctrlKey && duplicatedObjects.length === 0) { + if (controls) (controls as any).enabled = false; + selectionBox.startPoint.set(pointer.x, pointer.y, 0); + } } }; const onPointerMove = (event: PointerEvent) => { + if (isRightClick) { + rightClickMoved = true; + } isSelecting = true; if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting) { selectionBox.endPoint.set(pointer.x, pointer.y, 0); @@ -69,6 +78,14 @@ const SelectionControls: React.FC = () => { }; const onPointerUp = (event: PointerEvent) => { + if (event.button === 2) { + isRightClick = false; + if (!rightClickMoved) { + clearSelection(); + } + return; + } + if (isSelecting && isCtrlSelecting) { isCtrlSelecting = false; isSelecting = false; @@ -94,10 +111,13 @@ const SelectionControls: React.FC = () => { } }; + const onContextMenu = (event: MouseEvent) => { event.preventDefault(); - clearSelection(); - } + if (!rightClickMoved) { + clearSelection(); + } + }; if (!toggleView && activeModule === "builder") { helper.enabled = true; diff --git a/app/src/modules/simulation/behaviour/behaviour.tsx b/app/src/modules/simulation/behaviour/behaviour.tsx index c1281b5..afb4ae9 100644 --- a/app/src/modules/simulation/behaviour/behaviour.tsx +++ b/app/src/modules/simulation/behaviour/behaviour.tsx @@ -2,16 +2,22 @@ import { useFloorItems, useSimulationPaths } from '../../../store/store'; import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; import { useEffect } from 'react'; +import { getAssetEventType } from '../../../services/simulation/getAssetEventType'; function Behaviour() { const { setSimulationPaths } = useSimulationPaths(); const { floorItems } = useFloorItems(); useEffect(() => { + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = []; floorItems.forEach((item: Types.FloorItemType) => { if (item.modelfileID === "672a090f80d91ac979f4d0bd") { + // getAssetEventType(item.modelfileID, organization).then((res) => { + // console.log('res: ', res); + // }); const point1Position = new THREE.Vector3(0, 0.85, 2.2); const middlePointPosition = new THREE.Vector3(0, 0.85, 0); const point2Position = new THREE.Vector3(0, 0.85, -2.2); @@ -67,7 +73,7 @@ function Behaviour() { point: { uuid: pointUUID, position: [pointPosition.x, pointPosition.y, pointPosition.z], - actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: '', hitCount: 1, end: '', buffer: 0 }, + actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: 'Start', start: {}, hitCount: 1, end: {}, buffer: 0 }, connections: { source: { pathUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, speed: 2, }, diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index 0888966..7352932 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -96,24 +96,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; const existingTargets = path.point.connections.targets || []; - // Check if we're trying to add a connection to a Conveyor + // Check if target is a Conveyor const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID); - const isConnectingToConveyor = toPath?.type === 'Conveyor'; - - // Count existing connections - if (existingTargets.length >= 2) { - console.log("Vehicle can have maximum 2 connections"); + if (toPath?.type !== 'Conveyor') { + console.log("Vehicle can only connect to Conveyors"); return path; } - // Check if we already have a Conveyor connection and trying to add another - const hasConveyorConnection = existingTargets.some(target => { - const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); - return targetPath?.type === 'Conveyor'; - }); - - if (hasConveyorConnection && isConnectingToConveyor) { - console.log("Vehicle can only have one connection to a Conveyor"); + // Check if already has a connection + if (existingTargets.length >= 1) { + console.log("Vehicle can have only one connection"); return path; } @@ -141,24 +133,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; const existingTargets = path.point.connections.targets || []; - // Check if we're receiving a connection from a Conveyor + // Check if source is a Conveyor const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID); - const isConnectingFromConveyor = fromPath?.type === 'Conveyor'; - - // Count existing connections - if (existingTargets.length >= 2) { - console.log("Vehicle can have maximum 2 connections"); + if (fromPath?.type !== 'Conveyor') { + console.log("Vehicle can only connect to Conveyors"); return path; } - // Check if we already have a Conveyor connection and trying to add another - const hasConveyorConnection = existingTargets.some(target => { - const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); - return targetPath?.type === 'Conveyor'; - }); - - if (hasConveyorConnection && isConnectingFromConveyor) { - console.log("Vehicle can only have one connection to a Conveyor"); + // Check if already has a connection + if (existingTargets.length >= 1) { + console.log("Vehicle can have only one connection"); return path; } @@ -212,6 +196,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec drag = true; } }; + const onContextMenu = (evt: MouseEvent) => { evt.preventDefault(); if (drag || evt.button === 0) return; @@ -282,7 +267,16 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return; } - // For Vehicles, skip the "already connected" check since they can have multiple connections + // For Vehicles, check if they're already connected to anything + if (intersected.userData.path.type === 'Vehicle') { + const vehicleConnections = intersected.userData.path.point.connections.targets.length; + if (vehicleConnections >= 1) { + console.log("Vehicle can only have one connection"); + return; + } + } + + // For non-Vehicle paths, check if already connected if (intersected.userData.path.type !== 'Vehicle') { const isAlreadyConnected = simulationPaths.some(path => { if (path.type === 'Conveyor') { @@ -300,48 +294,14 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } } - // Check vehicle connection limits - const checkVehicleConnections = (pathUUID: string) => { - const path = simulationPaths.find(p => p.modeluuid === pathUUID); - if (path?.type === 'Vehicle') { - return path.point.connections.targets.length >= 2; - } - return false; - }; - if (firstSelected) { - // Check if either selected point is from a Vehicle with max connections - if (checkVehicleConnections(firstSelected.pathUUID) || - checkVehicleConnections(pathUUID)) { - console.log("Vehicle already has maximum connections"); + // Check if trying to connect Vehicle to non-Conveyor + if ((firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') || + (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor')) { + console.log("Vehicle can only connect to Conveyors"); return; } - // Check if we're trying to add a second Conveyor connection to a Vehicle - if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') { - const hasConveyorConnection = firstPath.point.connections.targets.some(target => { - const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); - return targetPath?.type === 'Conveyor'; - }); - - if (hasConveyorConnection) { - console.log("Vehicle can only have one connection to a Conveyor"); - return; - } - } - - if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') { - const hasConveyorConnection = secondPath.point.connections.targets.some(target => { - const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID); - return targetPath?.type === 'Conveyor'; - }); - - if (hasConveyorConnection) { - console.log("Vehicle can only have one connection to a Conveyor"); - return; - } - } - // Prevent same-path connections if (firstSelected.pathUUID === pathUUID) { console.log("Cannot connect spheres on the same path."); @@ -478,28 +438,19 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return false; }); - // Check vehicle connection limits + // Check vehicle connection rules const isVehicleAtMaxConnections = pathData.type === 'Vehicle' && - pathData.point.connections.targets.length >= 2; - - const isVehicleConveyorConflict = - (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' && - firstPath.point.connections.targets.some(t => { - const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID); - return targetPath?.type === 'Conveyor'; - })) || - (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' && - secondPath.point.connections.targets.some(t => { - const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID); - return targetPath?.type === 'Conveyor'; - })); + pathData.point.connections.targets.length >= 1; + const isVehicleConnectingToNonConveyor = + (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') || + (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor'); if ( !isDuplicateConnection && !isVehicleToVehicle && !isNonVehicleAlreadyConnected && !isVehicleAtMaxConnections && - !isVehicleConveyorConflict && + !isVehicleConnectingToNonConveyor && firstSelected.sphereUUID !== sphereUUID && firstSelected.pathUUID !== pathUUID && (firstSelected.isCorner || isConnectable) diff --git a/app/src/modules/simulation/path/pathCreation.tsx b/app/src/modules/simulation/path/pathCreation.tsx index 33ca2f8..202c7e7 100644 --- a/app/src/modules/simulation/path/pathCreation.tsx +++ b/app/src/modules/simulation/path/pathCreation.tsx @@ -1,8 +1,8 @@ import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; -import { useRef, useState, useEffect } from 'react'; +import { useRef, useState, useEffect, useMemo } from 'react'; import { Sphere, TransformControls } from '@react-three/drei'; -import { useIsConnecting, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store'; +import { useEditingPoint, useEyeDropMode, useIsConnecting, usePreviewPosition, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store'; import { useFrame, useThree } from '@react-three/fiber'; import { useSubModuleStore } from '../../../store/useModuleStore'; @@ -10,13 +10,18 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject const { renderDistance } = useRenderDistance(); const { setSubModule } = useSubModuleStore(); const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere(); + const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); + const { editingPoint, setEditingPoint } = useEditingPoint(); + const { previewPosition, setPreviewPosition } = usePreviewPosition(); + const { raycaster, camera, pointer, gl } = useThree(); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { setSelectedPath } = useSelectedPath(); const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { isConnecting } = useIsConnecting(); - const { camera } = useThree(); - + const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const isMovingRef = useRef(false); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | null>(null); @@ -77,6 +82,83 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject setSimulationPaths(updatedPaths); }; + useFrame(() => { + if (eyeDropMode) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + + if (point) { + setPreviewPosition({ x: point.x, y: point.z }); + } + } else { + setPreviewPosition(null); + } + }); + + useEffect(() => { + if (!camera) return; + const canvasElement = gl.domElement; + canvasElement.tabIndex = 0; + + + const onPointerDown = () => { + isMovingRef.current = false; + }; + + const onPointerMove = () => { + isMovingRef.current = true; + }; + + const onPointerUp = (event: PointerEvent) => { + if (!isMovingRef.current && eyeDropMode && event.button === 0 && previewPosition) { + event.preventDefault(); + if (editingPoint) { + handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y); + setEditingPoint(null); + setEyeDropMode(false); + } + } + }; + + if (eyeDropMode) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + } + + return () => { + canvasElement.removeEventListener("pointerdown", onPointerDown); + canvasElement.removeEventListener("pointermove", onPointerMove); + canvasElement.removeEventListener("pointerup", onPointerUp); + }; + }, [eyeDropMode, editingPoint, previewPosition]); + + const handlePointUpdate = (pointType: 'start' | 'end', x: number, z: number) => { + if (!selectedActionSphere?.point?.uuid) return; + + const updatedPaths = simulationPaths.map((path) => { + if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) { + return { + ...path, + point: { + ...path.point, + actions: { + ...path.point.actions, + [pointType]: { + ...path.point.actions[pointType], + x: x, + y: z + } + } + } + }; + } + return path; + }); + + setSimulationPaths(updatedPaths); + }; return ( @@ -92,7 +174,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject position={path.assetPosition} rotation={path.assetRotation} onClick={(e) => { - if (isConnecting) return; + if (isConnecting || eyeDropMode) return; e.stopPropagation(); setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); setSelectedActionSphere(null); @@ -100,6 +182,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject setSubModule('mechanics'); }} onPointerMissed={() => { + if (eyeDropMode) return; setSelectedPath(null); setSubModule('properties'); }} @@ -113,7 +196,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject name='events-sphere' ref={el => (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { - if (isConnecting) return; + if (isConnecting || eyeDropMode) return; e.stopPropagation(); setSelectedActionSphere({ path, @@ -124,6 +207,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }} userData={{ point, path }} onPointerMissed={() => { + if (eyeDropMode) return; setSubModule('properties'); setSelectedActionSphere(null); }} @@ -155,7 +239,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject ref={el => (groupRefs.current[path.modeluuid] = el!)} position={path.assetPosition} onClick={(e) => { - if (isConnecting) return; + if (isConnecting || eyeDropMode) return; e.stopPropagation(); setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); setSelectedActionSphere(null); @@ -163,6 +247,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject setSubModule('mechanics'); }} onPointerMissed={() => { + if (eyeDropMode) return; setSelectedPath(null); setSubModule('properties'); }} @@ -175,7 +260,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject name='events-sphere' ref={el => (sphereRefs.current[path.point.uuid] = el!)} onClick={(e) => { - if (isConnecting) return; + if (isConnecting || eyeDropMode) return; e.stopPropagation(); setSelectedActionSphere({ path, @@ -186,6 +271,7 @@ function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }} userData={{ point: path.point, path }} onPointerMissed={() => { + if (eyeDropMode) return; setSubModule('properties'); setSelectedActionSphere(null); }} diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 10934fb..8e7a214 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,6 +1,5 @@ -import { useState, useEffect, useRef } from 'react'; +import { useState, useEffect, useRef, useMemo } from 'react'; import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store'; -import { useThree } from '@react-three/fiber'; import * as THREE from 'three'; import Behaviour from './behaviour/behaviour'; import PathCreation from './path/pathCreation'; @@ -29,9 +28,10 @@ function Simulation() { // } // }, [selectedPath]); + return ( <> - + {activeModule === 'simulation' && ( <> diff --git a/app/src/services/simulation/getAssetEventType.ts b/app/src/services/simulation/getAssetEventType.ts new file mode 100644 index 0000000..e516feb --- /dev/null +++ b/app/src/services/simulation/getAssetEventType.ts @@ -0,0 +1,26 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_TEST}`; + +export const getAssetEventType = async (modelId: string, organization: string) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/pointData/${modelId}/${organization}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error("Failed to fetch model event type"); + } + + const result = await response.json(); + console.log('result: ', result); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/store/store.ts b/app/src/store/store.ts index a64f417..9688448 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -348,10 +348,30 @@ export const useStartSimulation = create((set: any) => ({ startSimulation: false, setStartSimulation: (x: any) => set({ startSimulation: x }), })); + +export const useEyeDropMode = create((set: any) => ({ + eyeDropMode: false, + setEyeDropMode: (x: any) => set({ eyeDropMode: x }), +})); + +export const useEditingPoint = create((set: any) => ({ + editingPoint: false, + setEditingPoint: (x: any) => set({ editingPoint: x }), +})); + +export const usePreviewPosition = create<{ + previewPosition: { x: number; y: number } | null; + setPreviewPosition: (position: { x: number; y: number } | null) => void; +}>((set) => ({ + previewPosition: null, + setPreviewPosition: (position) => set({ previewPosition: position }), +})); + export const usezoneTarget = create((set: any) => ({ zoneTarget: [], setZoneTarget: (x: any) => set({ zoneTarget: x }), })); + export const usezonePosition = create((set: any) => ({ zonePosition: [], setZonePosition: (x: any) => set({ zonePosition: x }), @@ -371,6 +391,7 @@ export const useAsset3dWidget = create((set: any) => ({ widgetSelect: "", setWidgetSelect: (x: any) => set({ widgetSelect: x }), })); + export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 31c032c..3e40f40 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -310,7 +310,7 @@ interface VehicleEventsSchema { point: { uuid: string; position: [number, number, number]; - actions: { uuid: string; name: string; type: string; start: string, hitCount: number, end: string, buffer: number }; + actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; speed: number; }; From e54c9e6e0dd718af44ed983ec21d382a01d05b76 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 31 Mar 2025 14:52:06 +0530 Subject: [PATCH 04/11] Refactor Tools component for improved readability and structure --- app/src/components/ui/Tools.tsx | 88 +++++++++++++++------------------ 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 012142e..3333282 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -68,7 +68,7 @@ const Tools: React.FC = () => { : true ); }, []); - useEffect(() => {}, [activeModule]); + useEffect(() => { }, [activeModule]); useEffect(() => { setActiveTool(activeSubTool); setActiveSubTool(activeSubTool); @@ -210,9 +210,8 @@ const Tools: React.FC = () => {
{activeSubTool == "cursor" && (
{ setActiveTool("cursor"); }} @@ -222,9 +221,8 @@ const Tools: React.FC = () => { )} {activeSubTool == "free-hand" && (
{ setActiveTool("free-hand"); }} @@ -234,9 +232,8 @@ const Tools: React.FC = () => { )} {activeSubTool == "delete" && (
{ setActiveTool("delete"); }} @@ -308,9 +305,8 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-wall"); }} @@ -319,9 +315,8 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-zone"); }} @@ -330,9 +325,8 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-aisle"); }} @@ -341,9 +335,8 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-floor"); }} @@ -359,9 +352,8 @@ const Tools: React.FC = () => {
{ setActiveTool("measure"); }} @@ -377,9 +369,8 @@ const Tools: React.FC = () => {
{ setActiveTool("pen"); }} @@ -411,9 +402,8 @@ const Tools: React.FC = () => {
{ setActiveTool("comment"); }} @@ -422,9 +412,8 @@ const Tools: React.FC = () => {
{toggleThreeD && (
{ setIsPlaying(!isPlaying); }} @@ -433,20 +422,23 @@ const Tools: React.FC = () => {
)}
-
-
-
- 2d -
-
- 3d -
-
+ {activeModule === "builder" && ( + <> +
+
+
+ 2d +
+
+ 3d +
+
+ + )}
) : ( From ec87acb82461688ad2efa4a14443b57a1ec57bdd Mon Sep 17 00:00:00 2001 From: gabriel Date: Mon, 31 Mar 2025 15:02:35 +0530 Subject: [PATCH 05/11] added input for name --- app/.env | 2 + app/package-lock.json | 38 ++-- app/package.json | 1 + .../IotInputCards/LineGrapInput.tsx | 77 ++++--- .../sidebarRight/visualization/data/Data.tsx | 22 +- .../ui/componets/DraggableWidget.tsx | 9 +- .../realTimeVis/charts/BarGraphComponent.tsx | 19 +- .../charts/DoughnutGraphComponent.tsx | 202 +++++++++++++----- .../realTimeVis/charts/LineGraphComponent.tsx | 16 +- .../realTimeVis/charts/PieGraphComponent.tsx | 16 +- .../zoneData/addWidgets.ts | 2 +- .../zoneData/getSelect2dZoneData.ts | 2 +- .../zoneData/getZoneData.ts | 2 +- .../realTimeVisulization/zoneData/getZones.ts | 2 +- app/src/store/useChartStore.ts | 6 + 15 files changed, 281 insertions(+), 135 deletions(-) diff --git a/app/.env b/app/.env index 153338d..c93e3d1 100644 --- a/app/.env +++ b/app/.env @@ -7,6 +7,8 @@ REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 # Base URL for the server REST API, used for HTTP requests to the backend server. REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 +REACT_APP_SERVER_REST_API_LOCAL_BASE_URL=192.168.0.102:5000 + # Base URL for the server marketplace API. REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 diff --git a/app/package-lock.json b/app/package-lock.json index d3aa21e..7d72590 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -26,6 +26,7 @@ "@types/react-dom": "^18.3.0", "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", + "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", "leva": "^0.10.0", @@ -2018,7 +2019,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2030,7 +2031,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4263,25 +4264,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -8498,6 +8499,15 @@ "pnpm": ">=8" } }, + "node_modules/chartjs-plugin-annotation": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-3.1.0.tgz", + "integrity": "sha512-EkAed6/ycXD/7n0ShrlT1T2Hm3acnbFhgkIEJLa0X+M6S16x0zwj1Fv4suv/2bwayCT3jGPdAtI9uLcAMToaQQ==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=4.0.0" + } + }, "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", @@ -9006,7 +9016,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9874,7 +9884,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -15224,7 +15234,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20683,7 +20693,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20726,7 +20736,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20738,7 +20748,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21225,7 +21235,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22284,7 +22294,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/package.json b/app/package.json index 541d3a1..66e3b39 100644 --- a/app/package.json +++ b/app/package.json @@ -21,6 +21,7 @@ "@types/react-dom": "^18.3.0", "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", + "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", "leva": "^0.10.0", diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index baf1fcd..f36207e 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -58,11 +58,11 @@ // name: string; // fields: string; // } - + // interface InputData { // [key: string]: Measurement; // } - + // const extractMeasurements = (input: InputData): Measurement[] => { // return Object.values(input); // }; @@ -71,7 +71,7 @@ // const measurementsData = extractMeasurements(selections); // setMeasurements(measurementsData); // }, [selections]); - + // return ( // <> @@ -125,20 +125,22 @@ import useChartStore from "../../../../../store/useChartStore"; import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; type Props = {}; const LineGrapInput = (props: Props) => { - const { setMeasurements, updateDuration } = useChartStore(); + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); const [duration, setDuration] = useState('1h') const [dropDowndata, setDropDownData] = useState({}); - const [selections, setSelections] = useState>({}); + const [selections, setSelections] = useState>({}); const { selectedZone } = useSelectedZoneStore(); const { selectedChartId } = useWidgetStore(); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0] - + useEffect(() => { const fetchZoneData = async () => { try { @@ -157,13 +159,14 @@ const LineGrapInput = (props: Props) => { }, []); useEffect(() => { - const fetchSavedInputes = async() => { + const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); if (response.status === 200) { setSelections(response.data.Data.measurements) setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) } else { console.log("Unexpected response:", response); } @@ -181,17 +184,19 @@ const LineGrapInput = (props: Props) => { useEffect(() => { setMeasurements(selections); updateDuration(duration); - }, [selections, duration]); + updateName(widgetName); + }, [selections, duration, widgetName]); - const sendInputes = async(inputMeasurement: any, inputDuration: any) => { + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { try { - const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`,{ + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/widget/save`, { organization: organization, zoneId: selectedZone.zoneId, - widget:{ + widget: { id: selectedChartId.id, panel: selectedChartId.panel, + widgetName: inputName, Data: { measurements: inputMeasurement, duration: inputDuration @@ -210,35 +215,47 @@ const LineGrapInput = (props: Props) => { } } - const handleSelect = async(inputKey: string, selectedData: { name: string; fields: string } | null) => { - - // async() => { - const newSelections = { ...selections }; - if (selectedData === null) { - delete newSelections[inputKey]; - } else { - newSelections[inputKey] = selectedData; - } - // setMeasurements(newSelections); // Update Zustand store - console.log(newSelections); - if ( await sendInputes(newSelections, duration)) { - setSelections(newSelections); - } - // sendInputes(newSelections, duration); // Send data to server - // return newSelections; + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; // }; }; - const handleSelectDuration = async(option: string) => { - if ( await sendInputes(selections, option)) { + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { setDuration(option); } // setDuration(option); }; + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + return ( <>
+
+
Widget name
+ +
{[...Array(6)].map((_, index) => { const inputKey = `input${index + 1}`; return ( diff --git a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx index 71847c7..1100954 100644 --- a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx +++ b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx @@ -3,6 +3,7 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore"; import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown"; import LineGrapInput from "../IotInputCards/LineGrapInput"; +import RenameInput from "../../../../ui/inputs/RenameInput"; // Define the data structure for demonstration purposes const DATA_STRUCTURE = { @@ -107,27 +108,32 @@ const Data = () => { [selectedChartId.id]: currentChartData.map((group) => group.id === groupId ? { - ...group, - children: group.children.filter( - (child) => child.id !== childId - ), - } + ...group, + children: group.children.filter( + (child) => child.id !== childId + ), + } : group ), }; }); }; + console.log("selectedChartId", selectedChartId); return (
- {selectedChartId?.title && ( + {/* {selectedChartId?.title && (
{selectedChartId?.title}
- )} + )} */} + + + {/* */} + {/* Render groups dynamically */} { chartDataGroups[selectedChartId?.id] && } - + {/* Info Box */}
i diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index 9c17c03..f79c55c 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -287,18 +287,11 @@ export const DraggableWidget = ({ )} {widget.type === "doughnut" && ( )} {widget.type === "polarArea" && ( diff --git a/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx index 26f7a4b..8a18d0f 100644 --- a/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx @@ -211,9 +211,10 @@ const BarGraphComponent = ({ fontWeight = "Regular", }: ChartComponentProps) => { const { themeColor } = useThemeStore(); - const { measurements: chartMeasurements, duration: chartDuration } = useChartStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const [measurements, setmeasurements] = useState({}); const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ labels: [], datasets: [], @@ -236,6 +237,10 @@ const BarGraphComponent = ({ ], }; + useEffect(() => { + console.log("titleeeeeeeeeeeeeeeeeee",title); + },[]) + // Memoize Theme Colors const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]); const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]); @@ -270,7 +275,7 @@ const BarGraphComponent = ({ plugins: { title: { display: true, - text: title, + text: name, font: chartFontStyle, }, legend: { @@ -285,7 +290,7 @@ const BarGraphComponent = ({ }, }, }), - [title, chartFontStyle] + [title, chartFontStyle, name] ); // useEffect(() => {console.log(measurements); @@ -304,15 +309,12 @@ const BarGraphComponent = ({ const startStream = () => { - console.log("inputtttttttttt",inputData); socket.emit("lineInput", inputData); }; socket.on("connect", startStream); socket.on("lineOutput", (response) => { - console.log("responce dataaaaaaaaa",response.data); - const responseData = response.data; // Extract timestamps and values @@ -343,10 +345,11 @@ const BarGraphComponent = ({ if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); if (response.status === 200) { setmeasurements(response.data.Data.measurements) setDuration(response.data.Data.duration) + setName(response.data.widgetName) } else { console.log("Unexpected response:", response); } @@ -365,7 +368,7 @@ const BarGraphComponent = ({ fetchSavedInputes(); } } - ,[chartMeasurements, chartDuration]) + ,[chartMeasurements, chartDuration, widgetName]) return 0 ? chartData : defaultData} options={options} />; }; diff --git a/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx index c1d5ac2..8a6adf8 100644 --- a/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx @@ -1,22 +1,64 @@ -import { useMemo } from "react"; -import { Doughnut, Line } from "react-chartjs-2"; +import React, { useEffect, useMemo, useState } from "react"; +import { Doughnut } from "react-chartjs-2"; +import io from "socket.io-client"; +import { useThemeStore } from "../../../../store/useThemeStore"; +import useChartStore from "../../../../store/useChartStore"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import axios from "axios"; interface ChartComponentProps { + id: string; type: any; title: string; fontFamily?: string; fontSize?: string; fontWeight?: "Light" | "Regular" | "Bold"; - data: any; } const DoughnutGraphComponent = ({ + id, + type, title, fontFamily, fontSize, fontWeight = "Regular", }: ChartComponentProps) => { - // Memoize Font Weight Mapping + const { themeColor } = useThemeStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + const defaultData = { + labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], + datasets: [ + { + label: "Dataset", + data: [12, 19, 3, 5, 2, 3], + backgroundColor: ["#6f42c1"], + borderColor: "#b392f0", + borderWidth: 1, + }, + ], + }; + + useEffect(() => { + console.log("titleeeeeeeeeeeeeeeeeee",title); + },[]) + + // Memoize Theme Colors + const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]); + const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]); + + // Memoize Font Styling const chartFontWeightMap = useMemo( () => ({ Light: "lighter" as const, @@ -26,19 +68,9 @@ const DoughnutGraphComponent = ({ [] ); - // Parse and Memoize Font Size - const fontSizeValue = useMemo( - () => (fontSize ? parseInt(fontSize) : 12), - [fontSize] - ); + const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]); + const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]); - // Determine and Memoize Font Weight - const fontWeightValue = useMemo( - () => chartFontWeightMap[fontWeight], - [fontWeight, chartFontWeightMap] - ); - - // Memoize Chart Font Style const chartFontStyle = useMemo( () => ({ family: fontFamily || "Arial", @@ -48,46 +80,110 @@ const DoughnutGraphComponent = ({ [fontFamily, fontSizeValue, fontWeightValue] ); - const options = useMemo( - () => ({ - responsive: true, - maintainAspectRatio: false, - plugins: { - title: { - display: true, - text: title, - font: chartFontStyle, - }, - legend: { - display: false, - }, - }, - scales: { - x: { - ticks: { - display: false, // This hides the x-axis labels + // Memoize Chart Options + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + title: { + display: true, + text: name, + font: chartFontStyle, + }, + legend: { + display: false, }, }, - }, - }), - [title, chartFontStyle] - ); + scales: { + // x: { + // ticks: { + // display: true, // This hides the x-axis labels + // }, + // }, + }, + }), + [title, chartFontStyle, name] + ); - const chartData = { - labels: ["January", "February", "March", "April", "May", "June", "July"], - datasets: [ - { - label: "My First Dataset", - data: [65, 59, 80, 81, 56, 55, 40], - backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) - borderColor: "#ffffff", // Keeping border color white - borderWidth: 2, - fill: false, - }, - ], - }; + // useEffect(() => {console.log(measurements); + // },[measurements]) - return ; + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lineInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lineOutput", (response) => { + const responseData = response.data; + + // Extract timestamps and values + const labels = responseData.time; + const datasets = Object.keys(measurements).map((key) => { + const measurement = measurements[key]; + const datasetKey = `${measurement.name}.${measurement.fields}`; + return { + label: datasetKey, + data: responseData[datasetKey]?.values ?? [], + backgroundColor: "#6f42c1", + borderColor: "#b392f0", + borderWidth: 1, + }; + }); + + setChartData({ labels, datasets }); + }); + + return () => { + socket.off("lineOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async() => { + + if (id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + + return 0 ? chartData : defaultData} options={options} />; }; -export default DoughnutGraphComponent; +export default DoughnutGraphComponent; \ No newline at end of file diff --git a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx index 34420fa..0425408 100644 --- a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx @@ -24,9 +24,10 @@ const LineGraphComponent = ({ fontWeight = "Regular", }: ChartComponentProps) => { const { themeColor } = useThemeStore(); - const { measurements: chartMeasurements, duration: chartDuration } = useChartStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const [measurements, setmeasurements] = useState({}); const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ labels: [], datasets: [], @@ -49,6 +50,10 @@ const LineGraphComponent = ({ ], }; + useEffect(() => { + console.log("titleeeeeeeeeeeeeeeeeee",title); + },[]) + // Memoize Theme Colors const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]); const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]); @@ -83,7 +88,7 @@ const LineGraphComponent = ({ plugins: { title: { display: true, - text: title, + text: name, font: chartFontStyle, }, legend: { @@ -98,7 +103,7 @@ const LineGraphComponent = ({ }, }, }), - [title, chartFontStyle] + [title, chartFontStyle, name] ); // useEffect(() => {console.log(measurements); @@ -153,10 +158,11 @@ const LineGraphComponent = ({ if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); if (response.status === 200) { setmeasurements(response.data.Data.measurements) setDuration(response.data.Data.duration) + setName(response.data.widgetName) } else { console.log("Unexpected response:", response); } @@ -175,7 +181,7 @@ const LineGraphComponent = ({ fetchSavedInputes(); } } - ,[chartMeasurements, chartDuration]) + ,[chartMeasurements, chartDuration, widgetName]) return 0 ? chartData : defaultData} options={options} />; }; diff --git a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx index 46516fa..8f32791 100644 --- a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx @@ -210,9 +210,10 @@ const PieChartComponent = ({ fontWeight = "Regular", }: ChartComponentProps) => { const { themeColor } = useThemeStore(); - const { measurements: chartMeasurements, duration: chartDuration } = useChartStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); const [measurements, setmeasurements] = useState({}); const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ labels: [], datasets: [], @@ -235,6 +236,10 @@ const PieChartComponent = ({ ], }; + useEffect(() => { + console.log("titleeeeeeeeeeeeeeeeeee",title); + },[]) + // Memoize Theme Colors const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]); const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]); @@ -269,7 +274,7 @@ const PieChartComponent = ({ plugins: { title: { display: true, - text: title, + text: name, font: chartFontStyle, }, legend: { @@ -284,7 +289,7 @@ const PieChartComponent = ({ // }, }, }), - [title, chartFontStyle] + [title, chartFontStyle, name] ); // useEffect(() => {console.log(measurements); @@ -339,10 +344,11 @@ const PieChartComponent = ({ if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); if (response.status === 200) { setmeasurements(response.data.Data.measurements) setDuration(response.data.Data.duration) + setName(response.data.widgetName) } else { console.log("Unexpected response:", response); } @@ -361,7 +367,7 @@ const PieChartComponent = ({ fetchSavedInputes(); } } - ,[chartMeasurements, chartDuration]) + ,[chartMeasurements, chartDuration, widgetName]) return 0 ? chartData : defaultData} options={options} />; }; diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 683943e..64be803 100644 --- a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts @@ -1,4 +1,4 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}`; export const addingWidgets = async ( zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 71d9c2f..f509a5d 100644 --- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts @@ -1,4 +1,4 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}`; console.log("url_Backend_dwinzo: ", url_Backend_dwinzo); export const getSelect2dZoneData = async ( diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index d2df867..5d84167 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts @@ -1,4 +1,4 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}`; export const getZone2dData = async (organization?: string) => { try { diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index 39031d8..32f850a 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,4 +1,4 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}`; export const getZoneData = async (zoneId: string, organization: string) => { try { diff --git a/app/src/store/useChartStore.ts b/app/src/store/useChartStore.ts index 4d61952..079b9ff 100644 --- a/app/src/store/useChartStore.ts +++ b/app/src/store/useChartStore.ts @@ -9,20 +9,26 @@ interface MeasurementStore { measurements: Record; // Change array to Record interval: number; duration: string; + name: string; setMeasurements: (newMeasurements: Record) => void; updateDuration: (newDuration: string) => void; + updateName: (newName: string) => void; } const useChartStore = create((set) => ({ measurements: {}, // Initialize as an empty object interval: 1000, duration: "1h", + name:'', setMeasurements: (newMeasurements) => set(() => ({ measurements: newMeasurements })), updateDuration: (newDuration) => set(() => ({ duration: newDuration })), + + updateName: (newName) => + set(() => ({ duration: newName })), })); export default useChartStore; From 9611ad69cf7e45ed1d7f7a08e85b201fd833cb8b Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Mon, 31 Mar 2025 18:22:40 +0530 Subject: [PATCH 06/11] updated distanceLine and fix drag bug --- .../components/ui/componets/DistanceLines.tsx | 93 +++++ .../ui/componets/DroppedFloatingWidgets.tsx | 391 ++++++++++++------ .../componets/functions/determinePosition.ts | 14 +- .../functions/getActiveProperties.ts | 26 +- .../zoneData/useFloatingDataStore.ts | 8 + app/src/store/useDroppedObjectsStore.ts | 2 + app/src/styles/pages/realTimeViz.scss | 152 +++++++ 7 files changed, 535 insertions(+), 151 deletions(-) create mode 100644 app/src/components/ui/componets/DistanceLines.tsx create mode 100644 app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts diff --git a/app/src/components/ui/componets/DistanceLines.tsx b/app/src/components/ui/componets/DistanceLines.tsx new file mode 100644 index 0000000..07cf202 --- /dev/null +++ b/app/src/components/ui/componets/DistanceLines.tsx @@ -0,0 +1,93 @@ +import React from "react"; + +interface DistanceLinesProps { + obj: { + position: { + top?: number | "auto"; + left?: number | "auto"; + right?: number | "auto"; + bottom?: number | "auto"; + }; + }; + activeEdges: { + vertical: "top" | "bottom"; + horizontal: "left" | "right"; + } | null; +} + +const DistanceLines: React.FC = ({ obj, activeEdges }) => { + if (!activeEdges) return null; + + return ( + <> + {activeEdges.vertical === "top" && typeof obj.position.top === "number" && ( +
+ {obj.position.top}px +
+ )} + + {activeEdges.vertical === "bottom" && + typeof obj.position.bottom === "number" && ( +
+ {obj.position.bottom}px +
+ )} + + {activeEdges.horizontal === "left" && + typeof obj.position.left === "number" && ( +
+ {obj.position.left}px +
+ )} + + {activeEdges.horizontal === "right" && + typeof obj.position.right === "number" && ( +
+ {obj.position.right}px +
+ )} + + ); +}; + +export default DistanceLines; \ No newline at end of file diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index bf19bb9..272051c 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -1,6 +1,5 @@ import { WalletIcon } from "../../icons/3dChartIcons"; import { useEffect, useRef, useState } from "react"; -import { Line } from "react-chartjs-2"; import { useDroppedObjectsStore, Zones, @@ -9,29 +8,61 @@ import useModuleStore from "../../../store/useModuleStore"; import { determinePosition } from "./functions/determinePosition"; import { getActiveProperties } from "./functions/getActiveProperties"; import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets"; +import { + DublicateIcon, + KebabIcon, + DeleteIcon, +} from "../../icons/ExportCommonIcons"; +import DistanceLines from "./DistanceLines"; // Import the DistanceLines component + +interface DraggingState { + zone: string; + index: number; + initialPosition: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + }; +} const DroppedObjects: React.FC = () => { const zones = useDroppedObjectsStore((state) => state.zones); - + const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( (state) => state.updateObjectPosition ); - const [draggingIndex, setDraggingIndex] = useState<{ - zone: string; - index: number; - } | null>(null); + const [draggingIndex, setDraggingIndex] = useState( + null + ); const [offset, setOffset] = useState<[number, number] | null>(null); - const positionRef = useRef<[number, number] | null>(null); + const [activeEdges, setActiveEdges] = useState<{ + vertical: "top" | "bottom"; + horizontal: "left" | "right"; + } | null>(null); // State to track active edges for distance lines + const [currentPosition, setCurrentPosition] = useState<{ + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + } | null>(null); // State to track the current position during drag const animationRef = useRef(null); const { activeModule } = useModuleStore(); - // Get the first zone and its objects - const zoneEntries = Object.entries(zones); - if (zoneEntries.length === 0) return null; // No zone, nothing to render - const [zoneName, zone] = zoneEntries[0]; // Only render the first zone + // Clean up animation frame on unmount + useEffect(() => { + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + }; + }, []); - // Handle pointer down event - function handlePointerDown(event: React.PointerEvent, index: number) { + const zoneEntries = Object.entries(zones); + if (zoneEntries.length === 0) return null; + const [zoneName, zone] = zoneEntries[0]; + + const handlePointerDown = (event: React.PointerEvent, index: number) => { const obj = zone.objects[index]; const container = document.getElementById("real-time-vis-canvas"); if (!container) return; @@ -40,41 +71,41 @@ const DroppedObjects: React.FC = () => { const relativeX = event.clientX - rect.left; const relativeY = event.clientY - rect.top; - // Determine which properties are active for this object + // Determine active properties for the initial position const [activeProp1, activeProp2] = getActiveProperties(obj.position); - // Calculate the offset based on the active properties + // Set active edges for distance lines + const vertical = activeProp1 === "top" ? "top" : "bottom"; + const horizontal = activeProp2 === "left" ? "left" : "right"; + setActiveEdges({ vertical, horizontal }); + + // Store the initial position strategy and active edges + setDraggingIndex({ + zone: zoneName, + index, + initialPosition: { ...obj.position }, + }); + + // Calculate offset from mouse to object edges let offsetX = 0; let offsetY = 0; if (activeProp1 === "top") { - offsetY = - relativeY - - (typeof obj.position.top === "number" ? obj.position.top : 0); - } else if (activeProp1 === "bottom") { - offsetY = - rect.height - - relativeY - - (typeof obj.position.bottom === "number" ? obj.position.bottom : 0); + offsetY = relativeY - (obj.position.top as number); + } else { + offsetY = rect.height - relativeY - (obj.position.bottom as number); } if (activeProp2 === "left") { - offsetX = - relativeX - - (typeof obj.position.left === "number" ? obj.position.left : 0); - } else if (activeProp2 === "right") { - offsetX = - rect.width - - relativeX - - (typeof obj.position.right === "number" ? obj.position.right : 0); + offsetX = relativeX - (obj.position.left as number); + } else { + offsetX = rect.width - relativeX - (obj.position.right as number); } - setDraggingIndex({ zone: zoneName, index }); setOffset([offsetY, offsetX]); - } + }; - // Handle pointer move event - function handlePointerMove(event: React.PointerEvent) { + const handlePointerMove = (event: React.PointerEvent) => { if (!draggingIndex || !offset) return; const container = document.getElementById("real-time-vis-canvas"); @@ -84,91 +115,194 @@ const DroppedObjects: React.FC = () => { const relativeX = event.clientX - rect.left; const relativeY = event.clientY - rect.top; - // Determine which properties are active for the dragged object - const obj = zone.objects[draggingIndex.index]; - const [activeProp1, activeProp2] = getActiveProperties(obj.position); + // Dynamically determine the current position strategy + const newPositionStrategy = determinePosition(rect, relativeX, relativeY); + const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy); - // Calculate the new position based on the active properties - let newX = 0; + // Update active edges for distance lines + const vertical = activeProp1 === "top" ? "top" : "bottom"; + const horizontal = activeProp2 === "left" ? "left" : "right"; + setActiveEdges({ vertical, horizontal }); + + // Calculate new position based on the active properties let newY = 0; - - if (activeProp2 === "left") { - newX = relativeX - offset[1]; - } else if (activeProp2 === "right") { - newX = rect.width - (relativeX + offset[1]); - } + let newX = 0; if (activeProp1 === "top") { newY = relativeY - offset[0]; - } else if (activeProp1 === "bottom") { + } else { newY = rect.height - (relativeY + offset[0]); } - // Ensure the object stays within the canvas boundaries + if (activeProp2 === "left") { + newX = relativeX - offset[1]; + } else { + newX = rect.width - (relativeX + offset[1]); + } + + // Apply boundaries newX = Math.max(0, Math.min(rect.width - 50, newX)); newY = Math.max(0, Math.min(rect.height - 50, newY)); - // Update the position reference - positionRef.current = [newY, newX]; + // Create new position object + const newPosition = { + ...newPositionStrategy, + [activeProp1]: newY, + [activeProp2]: newX, + // Clear opposite properties + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", + }; + + // Update the current position state for DistanceLines + setCurrentPosition(newPosition); - // Update the object's position using requestAnimationFrame for smoother animations if (!animationRef.current) { animationRef.current = requestAnimationFrame(() => { - if (positionRef.current) { - updateObjectPosition(zoneName, draggingIndex.index, { - ...obj.position, - [activeProp1]: positionRef.current[0], - [activeProp2]: positionRef.current[1], - }); - } + updateObjectPosition(zoneName, draggingIndex.index, newPosition); animationRef.current = null; }); } - } + }; - // Handle pointer up event - async function handlePointerUp(event: React.MouseEvent) { + const handlePointerUp = async (event: React.PointerEvent) => { try { if (!draggingIndex || !offset) return; - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; const container = document.getElementById("real-time-vis-canvas"); - if (!container) throw new Error("Canvas container not found"); + if (!container) return; const rect = container.getBoundingClientRect(); const relativeX = event.clientX - rect.left; const relativeY = event.clientY - rect.top; - // Recalculate the position using determinePosition - const newPosition = determinePosition(rect, relativeX, relativeY); + // Only now determine the final position strategy + const finalPosition = determinePosition(rect, relativeX, relativeY); + const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - // Validate the dragging index and get the object - if (!zone.objects[draggingIndex.index]) { - throw new Error("Dragged object not found in the zone"); + // Calculate final position using the new strategy + let finalY = 0; + let finalX = 0; + + if (activeProp1 === "top") { + finalY = relativeY - offset[0]; + } else { + finalY = rect.height - (relativeY + offset[0]); } - const obj = { ...zone.objects[draggingIndex.index], position: newPosition }; - let response = await addingFloatingWidgets(zone.zoneId, organization, obj); + + if (activeProp2 === "left") { + finalX = relativeX - offset[1]; + } else { + finalX = rect.width - (relativeX + offset[1]); + } + + // Apply boundaries + finalX = Math.max(0, Math.min(rect.width - 50, finalX)); + finalY = Math.max(0, Math.min(rect.height - 50, finalY)); + + const boundedPosition = { + ...finalPosition, + [activeProp1]: finalY, + [activeProp2]: finalX, + }; + + // Save to backend + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const response = await addingFloatingWidgets(zone.zoneId, organization, { + ...zone.objects[draggingIndex.index], + position: boundedPosition, + }); + if (response.message === "Widget updated successfully") { - updateObjectPosition(zoneName, draggingIndex.index, newPosition); + updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); } - // Reset states + // Clean up setDraggingIndex(null); setOffset(null); - + setActiveEdges(null); // Clear active edges + setCurrentPosition(null); // Reset current position if (animationRef.current) { cancelAnimationFrame(animationRef.current); animationRef.current = null; } } catch (error) { - + console.error("Error in handlePointerUp:", error); } - } + }; + const handleKebabClick = (id: string, event: React.MouseEvent) => { + event.stopPropagation(); + setOpenKebabId((prevId) => (prevId === id ? null : id)); + }; + + const renderObjectContent = (obj: any) => { + switch (obj.className) { + case "floating total-card": + return ( + <> +
+
{obj.header}
+
+
{obj.value}
+
{obj.per}
+
+
+
+ +
+ + ); + case "warehouseThroughput floating": + return ( + <> +
+

Warehouse Throughput

+

+ (+5) more in 2025 +

+
+
+ {/* */} +
+ + ); + case "fleetEfficiency floating": + return ( + <> +

Fleet Efficiency

+
+
+
+
+
+
+
+
+ 0% +
+
{obj.per}%
+
Optimal
+
+ 100% +
+ + ); + default: + return null; + } + }; return ( -
+
{zone.objects.map((obj, index) => (
{ style={{ position: "absolute", top: - typeof obj.position.top !== "string" + typeof obj.position.top === "number" ? `${obj.position.top}px` : "auto", left: - typeof obj.position.left !== "string" + typeof obj.position.left === "number" ? `${obj.position.left}px` : "auto", right: - typeof obj.position.right !== "string" + typeof obj.position.right === "number" ? `${obj.position.right}px` : "auto", bottom: - typeof obj.position.bottom !== "string" + typeof obj.position.bottom === "number" ? `${obj.position.bottom}px` : "auto", - // transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out", }} onPointerDown={(event) => handlePointerDown(event, index)} > - {obj.className === "floating total-card" ? ( - <> -
-
{obj.header}
-
-
{obj.value}
-
{obj.per}
+ {renderObjectContent(obj)} +
handleKebabClick(obj.id, event)} + > + +
+ {openKebabId === obj.id && ( +
+
+
+
+
Duplicate
-
- -
- - ) : obj.className === "warehouseThroughput floating" ? ( - <> -
-

Warehouse Throughput

-

- (+5) more in 2025 -

-
-
- {/* */} -
- - ) : obj.className === "fleetEfficiency floating" ? ( - <> -

Fleet Efficiency

-
-
-
-
-
+
+
+
+
Delete
-
- 0% -
-
{obj.per}%
-
Optimal
-
- 100% -
- - ) : null} +
+ )}
))} + + {/* Render DistanceLines component during drag */} + {draggingIndex !== null && + activeEdges !== null && + currentPosition !== null && ( + + )}
); }; export default DroppedObjects; + +// in pointer move even when i goes to top right the value not changes to top right same problem in bottom left diff --git a/app/src/components/ui/componets/functions/determinePosition.ts b/app/src/components/ui/componets/functions/determinePosition.ts index 0fcd727..82f2303 100644 --- a/app/src/components/ui/componets/functions/determinePosition.ts +++ b/app/src/components/ui/componets/functions/determinePosition.ts @@ -8,11 +8,9 @@ export function determinePosition( right: number | "auto"; bottom: number | "auto"; } { - // Calculate the midpoints of the canvas const centerX = canvasRect.width / 2; const centerY = canvasRect.height / 2; - // Initialize position with default values let position: { top: number | "auto"; left: number | "auto"; @@ -21,9 +19,8 @@ export function determinePosition( }; if (relativeY < centerY) { - // Top half if (relativeX < centerX) { - // Left side + console.log("Top-left"); position = { top: relativeY, left: relativeX, @@ -31,7 +28,7 @@ export function determinePosition( bottom: "auto", }; } else { - // Right side + console.log("Top-right"); position = { top: relativeY, right: canvasRect.width - relativeX, @@ -40,9 +37,8 @@ export function determinePosition( }; } } else { - // Bottom half if (relativeX < centerX) { - // Left side + console.log("Bottom-left"); position = { bottom: canvasRect.height - relativeY, left: relativeX, @@ -50,7 +46,7 @@ export function determinePosition( top: "auto", }; } else { - // Right side + console.log("Bottom-right"); position = { bottom: canvasRect.height - relativeY, right: canvasRect.width - relativeX, @@ -61,4 +57,4 @@ export function determinePosition( } return position; -} +} \ No newline at end of file diff --git a/app/src/components/ui/componets/functions/getActiveProperties.ts b/app/src/components/ui/componets/functions/getActiveProperties.ts index 2cb0b1b..1a05d34 100644 --- a/app/src/components/ui/componets/functions/getActiveProperties.ts +++ b/app/src/components/ui/componets/functions/getActiveProperties.ts @@ -1,17 +1,11 @@ -export const getActiveProperties = (position: { - top: number | "auto"; - left: number | "auto"; - right: number | "auto"; - bottom: number | "auto"; -}) => { - let activeProps: ["top", "left"] | ["bottom", "right"] = ["top", "left"]; // Default to top-left - - if ( - typeof position.bottom !== "string" && - typeof position.right !== "string" - ) { - activeProps = ["bottom", "right"]; +export function getActiveProperties(position: any): [string, string] { + if (position.top !== "auto" && position.left !== "auto") { + return ["top", "left"]; // Top-left + } else if (position.top !== "auto" && position.right !== "auto") { + return ["top", "right"]; // Top-right + } else if (position.bottom !== "auto" && position.left !== "auto") { + return ["bottom", "left"]; // Bottom-left + } else { + return ["bottom", "right"]; // Bottom-right } - - return activeProps; -}; +} \ No newline at end of file diff --git a/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts b/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts new file mode 100644 index 0000000..39a542a --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts @@ -0,0 +1,8 @@ +import { create } from "zustand"; + +const useFloatingDataStore = create((set) => ({ + floatingdata: [], // Initial state + setfloatingadata: (newData: []) => set({ floatingdata: newData }), // Setter function +})); + +export default useFloatingDataStore; diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index dc648a9..5ded701 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -90,3 +90,5 @@ export interface Zones { zoneId: string; objects: DroppedObject[]; } + + diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 69df460..b080840 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -541,4 +541,156 @@ .zone.active { background-color: #007bff; color: white; +} + + + +.floating-wrapper { + .icon { + width: 25px !important; + height: 25px !important; + background-color: transparent; + } + + .kebab { + width: 30px; + height: 30px; + position: absolute !important; + top: 0px; + right: 0px; + z-index: 10; + cursor: pointer; + @include flex-center; + } + + .kebab-options { + position: absolute; + top: 18px; + right: 5px; + transform: translate(0px, 0); + background-color: var(--background-color); + z-index: 10; + + display: flex; + flex-direction: column; + gap: 6px; + border-radius: 4px; + + box-shadow: var(--box-shadow-medium); + + .btn { + display: flex; + gap: 6px; + align-items: center; + padding: 5px 10px; + color: var(--text-color); + cursor: pointer; + + &:hover { + .label { + color: var(--accent-color); + } + } + + &:hover { + background-color: var(--highlight-accent-color); + width: 100%; + + svg { + &:first-child { + fill: var(--accent-color); + } + + &:last-child { + fill: auto; + stroke: var(--accent-color); + } + } + } + } + + .dublicate { + cursor: not-allowed; + } + + + + } +} + + + + + + + + + + +/* General styles for all distance lines */ +.distance-line { + position: absolute; + border-style: dashed; + border-color: var(--accent-color); /* Green color for visibility */ + border-width: 1px; + pointer-events: none; /* Ensure lins don't interfere with dragging */ + z-index: 10000; +} + +/* Label styles for displaying distance values */ +.distance-label { + position: absolute; + background-color: var(--accent-color); + color: white; + font-size: 12px; + padding: 2px 6px; + border-radius: 3px; + white-space: nowrap; + transform: translate(-50%, -50%); /* Center the label */ +} + +/* Specific styles for each type of line */ + +/* Top distance line */ +.distance-line.top { + border-bottom: none; /* Remove bottom border for a single line */ + width: 2px; /* Thin vertical line */ +} + +.distance-line.top .distance-label { + top: -10px; /* Position label above the line */ + left: 50%; /* Center horizontally */ +} + +/* Bottom distance line */ +.distance-line.bottom { + border-top: none; /* Remove top border for a single line */ + width: 2px; /* Thin vertical line */ +} + +.distance-line.bottom .distance-label { + bottom: -10px; /* Position label below the line */ + left: 50%; /* Center horizontally */ +} + +/* Left distance line */ +.distance-line.left { + border-right: none; /* Remove right border for a single line */ + height: 2px; /* Thin horizontal line */ +} + +.distance-line.left .distance-label { + left: -10px; /* Position label to the left of the line */ + top: 50%; /* Center vertically */ +} + +/* Right distance line */ +.distance-line.right { + border-left: none; /* Remove left border for a single line */ + height: 2px; /* Thin horizontal line */ +} + +.distance-line.right .distance-label { + right: -10px; /* Position label to the right of the line */ + top: 50%; /* Center vertically */ } \ No newline at end of file From 6b8ccc02c740f9b1c857b5b867a81c5096fd8dfa Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 31 Mar 2025 19:20:03 +0530 Subject: [PATCH 07/11] 3d widget api added and template frontend and backend completed --- .../sidebarLeft/visualization/Templates.tsx | 78 ++++++-- .../properties/ZoneProperties.tsx | 7 +- app/src/components/ui/Tools.tsx | 9 +- .../components/ui/componets/AddButtons.tsx | 1 - .../components/ui/componets/DisplayZone.tsx | 17 +- .../components/ui/componets/DistanceLine.tsx | 93 ++++++++++ .../ui/componets/Dropped3dWidget.tsx | 170 ++++++++++++------ .../ui/componets/DroppedFloatingWidgets.tsx | 52 +++++- .../ui/componets/RealTimeVisulization.tsx | 11 +- .../componets/functions/determinePosition.ts | 67 +++++++ .../ui/componets/handleDropTemplate .tsx | 29 +++ app/src/modules/simulation/simulation.tsx | 1 - .../visualization/handleSaveTemplate.ts | 61 ++++--- .../zoneData/add3dWidget.ts | 36 ++++ .../zoneData/addFloatingWidgets.ts | 1 + .../zoneData/deleteFloatingWidget.ts | 35 ++++ .../zoneData/deleteTemplate.ts | 32 ++++ .../zoneData/get3dWidgetData.ts | 25 +++ .../zoneData/getSelect2dZoneData.ts | 1 + .../zoneData/getTemplate.ts | 23 +++ .../realTimeVisulization/zoneData/getZones.ts | 2 +- .../zoneData/loadTemplate.ts | 33 ++++ .../zoneData/saveTempleteApi.ts | 28 +++ app/src/store/store.ts | 1 + app/src/store/useDroppedObjectsStore.ts | 77 ++++++++ app/src/store/useTemplateStore.ts | 18 +- app/src/styles/pages/realTimeViz.scss | 11 -- 27 files changed, 790 insertions(+), 129 deletions(-) create mode 100644 app/src/components/ui/componets/DistanceLine.tsx create mode 100644 app/src/components/ui/componets/handleDropTemplate .tsx create mode 100644 app/src/services/realTimeVisulization/zoneData/add3dWidget.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/getTemplate.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/loadTemplate.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index ef710f7..4b13429 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -1,25 +1,76 @@ +import { useEffect } from "react"; +import { useDroppedObjectsStore } from "../../../../store/useDroppedObjectsStore"; import useTemplateStore from "../../../../store/useTemplateStore"; import { useSelectedZoneStore } from "../../../../store/useZoneStore"; +import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate"; +import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate"; +import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate"; const Templates = () => { const { templates, removeTemplate } = useTemplateStore(); - const { setSelectedZone } = useSelectedZoneStore(); + const { setTemplates } = useTemplateStore(); + const { setSelectedZone, selectedZone } = useSelectedZoneStore(); - const handleDeleteTemplate = (id: string) => { - removeTemplate(id); + useEffect(() => { + async function templateData() { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + let response = await getTemplateData(organization); + setTemplates(response); + } catch (error) { + console.error("Error fetching template data:", error); + } + } + + templateData(); + }, []); + + const handleDeleteTemplate = async (id: string) => { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + let response = await deleteTemplateApi(id, organization); + + if (response.message === "Template deleted successfully") { + removeTemplate(id); + } + } catch (error) { + console.error("Error deleting template:", error); + } }; - const handleLoadTemplate = (template: any) => { - setSelectedZone((prev) => ({ - ...prev, - panelOrder: template.panelOrder, - activeSides: Array.from( - new Set([...prev.activeSides, ...template.panelOrder]) - ), - widgets: template.widgets, - })); + const handleLoadTemplate = async (template: any) => { + try { + if (selectedZone.zoneName === "") return; + + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization); + + if (response.message === "Template placed in Zone") { + setSelectedZone({ + panelOrder: template.panelOrder, + activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` + widgets: template.widgets, + }); + + useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); + + if (Array.isArray(template.floatingWidget)) { + template.floatingWidget.forEach((val: any) => { + useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); + }); + } + } + } catch (error) { + console.error("Error loading template:", error); + } }; + return (
{ transition: "box-shadow 0.3s ease", }} > - {template.snapshot && ( + {template?.snapshot && (
{" "} {/* 16:9 aspect ratio */} @@ -122,3 +173,4 @@ const Templates = () => { }; export default Templates; + diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 9234cc5..9e8b37e 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -20,17 +20,16 @@ const ZoneProperties: React.FC = () => { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - + let zonesdata = { zoneId: selectedZone.zoneId, viewPortposition: zonePosition, viewPortCenter: zoneTarget }; - + let response = await zoneCameraUpdate(zonesdata, organization); console.log('response: ', response); - - + setEdit(false); } catch (error) { console.error("Error in handleSetView:", error); diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index c86164c..ba1f6e8 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -32,6 +32,7 @@ import { useTransformMode, } from "../../store/store"; import useToggleStore from "../../store/useUIToggleStore"; +import { use3DWidget, useFloatingWidget } from "../../store/useDroppedObjectsStore"; const Tools: React.FC = () => { const { templates } = useTemplateStore(); @@ -46,6 +47,8 @@ const Tools: React.FC = () => { const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { addTemplate } = useTemplateStore(); const { selectedZone } = useSelectedZoneStore(); + const { floatingWidget } = useFloatingWidget() + const { widgets3D } = use3DWidget() // wall options const { toggleView, setToggleView } = useToggleView(); @@ -378,13 +381,17 @@ const Tools: React.FC = () => {
+ onClick={() => { + handleSaveTemplate({ addTemplate, + floatingWidget, + widgets3D, selectedZone, templates, }) } + } >
diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 4f3f9b7..e0ca342 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -119,7 +119,6 @@ const AddButtons: React.FC = ({ }; // Delete the selectedZone state - setSelectedZone(updatedZone); } else { const updatePanelData = async () => { diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 7689e51..3889139 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -2,9 +2,10 @@ import React, { useEffect, useRef, useState, useCallback } from "react"; import { Widget } from "../../../store/useWidgetStore"; import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons"; import { InfoIcon } from "../../icons/ExportCommonIcons"; -import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; +import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore"; import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData"; import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData"; +import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -72,6 +73,7 @@ const DisplayZone: React.FC = ({ // State to track overflow visibility const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); + const { floatingWidget, setFloatingWidget } = useFloatingWidget() // Function to calculate overflow state const updateOverflowState = useCallback(() => { @@ -150,14 +152,16 @@ const DisplayZone: React.FC = ({ async function handleSelect2dZoneData(zoneId: string, zoneName: string) { try { if (selectedZone?.zoneId === zoneId) { - console.log("Zone is already selected:", zoneName); + return; } const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fetch data from backend let response = await getSelect2dZoneData(zoneId, organization); + console.log('response: ', response); let res = await getFloatingZoneData(zoneId, organization); + setFloatingWidget(res) // Set the selected zone in the store useDroppedObjectsStore.getState().setZone(zoneName, zoneId); if (Array.isArray(res)) { @@ -177,8 +181,8 @@ const DisplayZone: React.FC = ({ zoneViewPortPosition: response.viewPortposition || {}, }); } catch (error) { - console.log('error: ', error); - + + } } @@ -186,9 +190,8 @@ const DisplayZone: React.FC = ({ return (
{/* Left Arrow */} {showLeftArrow && ( diff --git a/app/src/components/ui/componets/DistanceLine.tsx b/app/src/components/ui/componets/DistanceLine.tsx new file mode 100644 index 0000000..8dec7b1 --- /dev/null +++ b/app/src/components/ui/componets/DistanceLine.tsx @@ -0,0 +1,93 @@ +import React from "react"; + +interface DistanceLinesProps { + obj: { + position: { + top?: number | "auto"; + left?: number | "auto"; + right?: number | "auto"; + bottom?: number | "auto"; + }; + }; + activeEdges: { + vertical: "top" | "bottom"; + horizontal: "left" | "right"; + } | null; +} + +const DistanceLines: React.FC = ({ obj, activeEdges }) => { + if (!activeEdges) return null; + + return ( + <> + {activeEdges.vertical === "top" && typeof obj.position.top === "number" && ( +
+ {obj.position.top.toFixed()}px +
+ )} + + {activeEdges.vertical === "bottom" && + typeof obj.position.bottom === "number" && ( +
+ {obj.position.bottom.toFixed()}px +
+ )} + + {activeEdges.horizontal === "left" && + typeof obj.position.left === "number" && ( +
+ {obj.position.left.toFixed()}px +
+ )} + + {activeEdges.horizontal === "right" && + typeof obj.position.right === "number" && ( +
+ {obj.position.right.toFixed()}px +
+ )} + + ); +}; + +export default DistanceLines; \ No newline at end of file diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 10dd343..c627af4 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -10,79 +10,139 @@ import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity"; import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment"; import StateWorking from "../../layout/3D-cards/cards/StateWorking"; import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { generateUniqueId } from "../../../functions/generateUniqueId"; +import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget"; +import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; +import { use3DWidget } from "../../../store/useDroppedObjectsStore"; export default function Dropped3dWidgets() { - const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); + const { widgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); const { raycaster, gl, scene }: ThreeState = useThree(); - const { selectedZone } = useSelectedZoneStore(); // Get currently selected zone - const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption() - // 🔥 Store widget positions per zone - const [zoneWidgets, setZoneWidgets] = useState // Widget type -> Positions array - >>({}); - + const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); + const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone + // 🔥 Store widget data (id, type, position) based on the selected zone + const [zoneWidgetData, setZoneWidgetData] = useState< + Record + >({}); + const { setWidgets3D } = use3DWidget() useEffect(() => { - if (widgetSubOption === "Floating") return - // if (activeModule !== "visualization") return; - const canvasElement = gl.domElement; - const onDrop = (event: DragEvent) => { - event.preventDefault(); // Prevent default browser behavior - if (widgetSubOption === "3D") { - if (selectedZone.zoneName === "") return - if (!widgetSelect?.startsWith("ui")) return; - const group1 = scene.getObjectByName("itemsGroup"); - if (!group1) return; - const Assets = group1.children - .map((val) => scene.getObjectByProperty("uuid", val.uuid)) - .filter(Boolean) as THREE.Object3D[]; - const intersects = raycaster.intersectObjects(scene.children, true).filter( - (intersect) => - !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("agv-collider") && - !intersect.object.name.includes("MeasurementReference") && - !intersect.object.userData.isPathObject && - !(intersect.object.type === "GridHelper") - ); - if (intersects.length > 0) { - const { x, y, z } = intersects[0].point; + if (activeModule !== "visualization") return + if (selectedZone.zoneName === "") return; - setZoneWidgets((prev) => ({ - ...prev, - [selectedZone.zoneId]: { - ...(prev[selectedZone.zoneId] || {}), - [widgetSelect]: [...(prev[selectedZone.zoneId]?.[widgetSelect] || []), [x, y, z]], - }, - })); - } + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + async function get3dWidgetData() { + let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); + setWidgets3D(result) + // Ensure the extracted data has id, type, and position correctly mapped + const formattedWidgets = result.map((widget: any) => ({ + id: widget.id, + type: widget.type, + position: widget.position, + })); + + setZoneWidgetData((prev) => ({ + ...prev, + [selectedZone.zoneId]: formattedWidgets, + })); + } + + get3dWidgetData(); + + }, [selectedZone.zoneId,activeModule]); + // useEffect(() => { + // // ✅ Set data only for the selected zone, keeping existing state structure + // setZoneWidgetData((prev) => ({ + // ...prev, + // [selectedZone.zoneId]: [ + // { + // "id": "1743322674626-50mucpb1c", + // "type": "ui-Widget 1", + // "position": [120.94655021768133, 4.142360029666558, 124.39283546121099] + // }, + // { + // "id": "1743322682086-je2h9x33v", + // "type": "ui-Widget 2", + // "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362] + // } + // ] + // })); + // }, [selectedZone.zoneId]); // ✅ Only update when the zone changes + + useEffect(() => { + if (activeModule !== "visualization") return; + if (widgetSubOption === "Floating") return; + if (selectedZone.zoneName === "") return + const canvasElement = gl.domElement; + const onDrop = async (event: DragEvent) => { + event.preventDefault(); // Prevent default browser behavior + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + if (!widgetSelect.startsWith("ui")) return; + const group1 = scene.getObjectByName("itemsGroup"); + if (!group1) return; + const intersects = raycaster.intersectObjects(scene.children, true).filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.userData.isPathObject && + !(intersect.object.type === "GridHelper") + ); + if (intersects.length > 0) { + const { x, y, z } = intersects[0].point; + + // ✅ Explicitly define position as a tuple + const newWidget: { id: string; type: string; position: [number, number, number] } = { + id: generateUniqueId(), + type: widgetSelect, + position: [x, y, z], // Ensures TypeScript recognizes it as a tuple + }; + + + let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) + + + // ✅ Store widgets uniquely for each zone + setZoneWidgetData((prev) => ({ + ...prev, + [selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget], + })); } }; + canvasElement.addEventListener("drop", onDrop); return () => { - canvasElement.removeEventListener("drop", onDrop) - // setWidgetSelect() + canvasElement.removeEventListener("drop", onDrop); }; - }, [widgetSelect, activeModule, widgetSubOption]); + }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]); + + // Get widgets for the currently active zone + const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; return ( <> - {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 1"]?.map((pos, index) => ( - - ))} - {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 2"]?.map((pos, index) => ( - - ))} - {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 3"]?.map((pos, index) => ( - - ))} - {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 4"]?.map((pos, index) => ( - - ))} + {activeZoneWidgets.map(({ id, type, position }) => { + switch (type) { + case "ui-Widget 1": + return ; + case "ui-Widget 2": + return ; + case "ui-Widget 3": + return ; + case "ui-Widget 4": + return ; + default: + return null; + } + })} ); } + diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 272051c..5526902 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -1,3 +1,4 @@ + import { WalletIcon } from "../../icons/3dChartIcons"; import { useEffect, useRef, useState } from "react"; import { @@ -14,6 +15,7 @@ import { DeleteIcon, } from "../../icons/ExportCommonIcons"; import DistanceLines from "./DistanceLines"; // Import the DistanceLines component +import { deleteFloatingWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteFloatingWidget"; interface DraggingState { zone: string; @@ -26,12 +28,25 @@ interface DraggingState { }; } +interface DraggingState { + zone: string; + index: number; + initialPosition: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + }; +} const DroppedObjects: React.FC = () => { const zones = useDroppedObjectsStore((state) => state.zones); const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( (state) => state.updateObjectPosition ); + const deleteObject = useDroppedObjectsStore((state) => state.deleteObject); + + const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject); const [draggingIndex, setDraggingIndex] = useState( null ); @@ -62,6 +77,28 @@ const DroppedObjects: React.FC = () => { if (zoneEntries.length === 0) return null; const [zoneName, zone] = zoneEntries[0]; + function handleDuplicate(zoneName: string, index: number) { + setOpenKebabId(null) + duplicateObject(zoneName, index); // Call the duplicateObject method from the store + } + + async function handleDelete(zoneName: string, id: string, index: number) { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + let res = await deleteFloatingWidgetApi(id, organization); + console.log('res: ', res); + + if (res.message === "FloatingWidget deleted successfully") { + deleteObject(zoneName, index); // Call the deleteObject method from the store + } + } catch (error) { + console.error("Error deleting floating widget:", error); + } + } + + const handlePointerDown = (event: React.PointerEvent, index: number) => { const obj = zone.objects[index]; const container = document.getElementById("real-time-vis-canvas"); @@ -228,11 +265,12 @@ const DroppedObjects: React.FC = () => { animationRef.current = null; } } catch (error) { - console.error("Error in handlePointerUp:", error); + } }; const handleKebabClick = (id: string, event: React.MouseEvent) => { + event.stopPropagation(); setOpenKebabId((prevId) => (prevId === id ? null : id)); }; @@ -337,13 +375,19 @@ const DroppedObjects: React.FC = () => {
{openKebabId === obj.id && (
-
+
{ + event.stopPropagation(); + handleDuplicate(zoneName, index); // Call the duplicate handler + }}>
Duplicate
-
+
{ + event.stopPropagation(); + handleDelete(zoneName, obj.id, index); // Call the delete handler + }}>
@@ -388,4 +432,4 @@ const DroppedObjects: React.FC = () => { export default DroppedObjects; -// in pointer move even when i goes to top right the value not changes to top right same problem in bottom left + diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 45db987..3f81518 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -63,6 +63,7 @@ const RealTimeVisulization: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; try { const response = await getZone2dData(organization); + if (!Array.isArray(response)) { return; } @@ -83,7 +84,7 @@ const RealTimeVisulization: React.FC = () => { ); setZonesData(formattedData); } catch (error) { - console.log("error: ", error); + } } @@ -109,7 +110,7 @@ const RealTimeVisulization: React.FC = () => { }); }, [selectedZone]); - useEffect(() => {}, [floatingWidgets]); + // useEffect(() => {}, [floatingWidgets]); const handleDrop = async (event: React.DragEvent) => { try { @@ -135,6 +136,7 @@ const RealTimeVisulization: React.FC = () => { id: generateUniqueId(), position: determinePosition(canvasRect, relativeX, relativeY), }; + console.log('newObject: ', newObject); let response = await addingFloatingWidgets( selectedZone.zoneId, @@ -150,7 +152,6 @@ const RealTimeVisulization: React.FC = () => { .getState() .setZone(selectedZone.zoneName, selectedZone.zoneId); } - // Add the dropped object to the zone if the API call is successful if (response.message === "FloatWidget created successfully") { useDroppedObjectsStore @@ -171,7 +172,7 @@ const RealTimeVisulization: React.FC = () => { ], }, })); - } catch (error) {} + } catch (error) { } }; return ( @@ -198,7 +199,7 @@ const RealTimeVisulization: React.FC = () => { >
- + {activeModule === "visualization" && selectedZone.zoneName !== "" && } {activeModule === "visualization" && ( <> { +// const { getTemplate } = useTemplateStore.getState(); +// const { setSelectedZone } = useSelectedZoneStore.getState(); + +// // Find the template by ID +// const template: Template | undefined = getTemplate(templateId); + +// if (!template) { +// console.error("Template not found!"); +// return; +// } + +// // Update the selected zone with the template data +// setSelectedZone((prev) => ({ +// ...prev, +// panelOrder: template.panelOrder, +// activeSides: Array.from(new Set([...prev.activeSides, ...template.panelOrder])), +// widgets: template.widgets, // Keep widget structure the same +// })); + +// console.log("Dropped template applied:", template); +// }; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 10934fb..0682f62 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -14,7 +14,6 @@ function Simulation() { const [processes, setProcesses] = useState([]); useEffect(() => { - console.log('simulationPaths: ', simulationPaths); }, [simulationPaths]); // useEffect(() => { diff --git a/app/src/modules/visualization/handleSaveTemplate.ts b/app/src/modules/visualization/handleSaveTemplate.ts index c489688..a71e654 100644 --- a/app/src/modules/visualization/handleSaveTemplate.ts +++ b/app/src/modules/visualization/handleSaveTemplate.ts @@ -1,74 +1,89 @@ +import { saveTemplateApi } from "../../services/realTimeVisulization/zoneData/saveTempleteApi"; import { Template } from "../../store/useTemplateStore"; import { captureVisualization } from "./captureVisualization"; type HandleSaveTemplateProps = { addTemplate: (template: Template) => void; + floatingWidget: []; // Updated type from `[]` to `any[]` for clarity + widgets3D: []; // Updated type from `[]` to `any[]` for clarity selectedZone: { - panelOrder: string[]; // Adjust the type based on actual data structure - widgets: any[]; // Replace `any` with the actual widget type + panelOrder: string[]; + widgets: any[]; }; templates?: Template[]; }; -// Generate a unique ID (placeholder function) +// Generate a unique ID const generateUniqueId = (): string => { return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`; }; -// Refactored function export const handleSaveTemplate = async ({ addTemplate, + floatingWidget, + widgets3D, selectedZone, templates = [], }: HandleSaveTemplateProps): Promise => { try { // Check if the selected zone has any widgets if (!selectedZone.widgets || selectedZone.widgets.length === 0) { - console.warn("Cannot save an empty template."); + console.warn("No widgets found in the selected zone."); return; } // Check if the template already exists - const isDuplicate = templates.some((template) => { - const isSamePanelOrder = + const isDuplicate = templates.some( + (template) => JSON.stringify(template.panelOrder) === - JSON.stringify(selectedZone.panelOrder); - const isSameWidgets = + JSON.stringify(selectedZone.panelOrder) && JSON.stringify(template.widgets) === - JSON.stringify(selectedZone.widgets); - return isSamePanelOrder && isSameWidgets; - }); + JSON.stringify(selectedZone.widgets) + ); if (isDuplicate) { - console.warn("This template already exists."); return; } // Capture visualization snapshot const snapshot = await captureVisualization(); - if (!snapshot) { - console.error("Failed to capture visualization snapshot."); - return; - } - + console.log("snapshot: ", snapshot); + // if (!snapshot) { + // return; + // } // Create a new template const newTemplate: Template = { id: generateUniqueId(), - name: `Template ${Date.now()}`, + name: `Template ${new Date().toISOString()}`, // Better name formatting panelOrder: selectedZone.panelOrder, widgets: selectedZone.widgets, snapshot, + floatingWidget, + widgets3D, }; - console.log("Saving template:", newTemplate); + // Extract organization from email + const email = localStorage.getItem("email") || ""; + const organization = email.includes("@") + ? email.split("@")[1]?.split(".")[0] + : ""; + + if (!organization) { + console.error("Organization could not be determined from email."); + return; + } // Save the template try { + const response = await saveTemplateApi(organization, newTemplate); + console.log("Save API Response:", response); + + // Add template only if API call succeeds addTemplate(newTemplate); - } catch (error) { - console.error("Failed to add template:", error); + } catch (apiError) { + console.error("Error saving template to API:", apiError); } } catch (error) { - console.error("Failed to save template:", error); + console.error("Error in handleSaveTemplate:", error); } }; diff --git a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts new file mode 100644 index 0000000..82562b7 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts @@ -0,0 +1,36 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const adding3dWidgets = async ( + zoneId: string, + organization: string, + widget: {} +) => { + console.log('widget: ', widget); + console.log('organization: ', organization); + console.log('zoneId: ', zoneId); + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/3dwidget/save`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, widget }), + } + ); + + if (!response.ok) { + throw new Error("Failed to add 3dwidget in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts index 338f26b..d73ec0d 100644 --- a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts @@ -1,5 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; // let url_Backend_dwinzo = `http://192.168.0.102:5000`; + export const addingFloatingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts new file mode 100644 index 0000000..85c96b8 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts @@ -0,0 +1,35 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; + +export const deleteFloatingWidgetApi = async ( + floatWidgetID: string, + organization: string +) => { + console.log('organization: ', organization); + console.log('floatWidgetID: ', floatWidgetID); + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/floatwidget/delete`, + { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, floatWidgetID }), + } + ); + + if (!response.ok) { + throw new Error("Failed to delete floating widget in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts new file mode 100644 index 0000000..e452f6d --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts @@ -0,0 +1,32 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; + +export const deleteTemplateApi = async ( + templateID: string, + organization?: string +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/TemplateDelete/${templateID}/${organization}`, + { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to delete template "); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts new file mode 100644 index 0000000..b5b6200 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts @@ -0,0 +1,25 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const get3dWidgetZoneData = async ( + ZoneId?: string, + organization?: string +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/3dwidgetData/${ZoneId}/${organization}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + if (!response.ok) { + throw new Error("Failed to fetch Zone3dWidgetData"); + } + + return await response.json(); + } catch (error: any) { + throw new Error(error.message); + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 26a88c5..00d4dfe 100644 --- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts @@ -1,4 +1,5 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getSelect2dZoneData = async ( ZoneId?: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts new file mode 100644 index 0000000..a3aa3a3 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts @@ -0,0 +1,23 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const getTemplateData = async (organization?: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/templateData/${organization}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to fetch ZoneFloatingData"); + } + + return await response.json(); + } catch (error: any) { + throw new Error(error.message); + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index a760959..8dbf79a 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,4 +1,5 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZoneData = async (zoneId: string, organization: string) => { console.log("organization: ", organization); @@ -14,7 +15,6 @@ export const getZoneData = async (zoneId: string, organization: string) => { } ); - if (!response.ok) { throw new Error("Failed to fetch zoneData"); } diff --git a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts new file mode 100644 index 0000000..915160d --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts @@ -0,0 +1,33 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const loadTempleteApi = async ( + templateID: string, + zoneId: string, + organization: string +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/TemplatetoZone`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, templateID }), + } + ); + + if (!response.ok) { + throw new Error("Failed to add 3dwidget in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts new file mode 100644 index 0000000..5c18031 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts @@ -0,0 +1,28 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const saveTemplateApi = async (organization: string, template: {}) => { + console.log('template: ', template); + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/template/save`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, template }), + }); + + if (!response.ok) { + throw new Error("Failed to save template zone"); + } + + const result = await response.json(); + console.log('result: ', result); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/store/store.ts b/app/src/store/store.ts index a64f417..f24da0c 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -375,3 +375,4 @@ export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); + diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index 5ded701..83f3a8a 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -1,4 +1,5 @@ import { create } from "zustand"; +import { addingFloatingWidgets } from "../services/realTimeVisulization/zoneData/addFloatingWidgets"; type DroppedObject = { className: string; @@ -35,6 +36,8 @@ type DroppedObjectsState = { bottom: number | "auto"; } ) => void; + deleteObject: (zoneName: string, index: number) => void; // Add this line + duplicateObject: (zoneName: string, index: number) => void; // Add this line }; export const useDroppedObjectsStore = create((set) => ({ @@ -73,6 +76,72 @@ export const useDroppedObjectsStore = create((set) => ({ }, }; }), + + deleteObject: (zoneName: string, index: number) => + set((state) => { + const zone = state.zones[zoneName]; + if (!zone) return state; + return { + zones: { + [zoneName]: { + ...zone, + objects: zone.objects.filter((_, i) => i !== index), // Remove object at the given index + }, + }, + }; + }), + duplicateObject: async (zoneName: string, index: number) => { + const state = useDroppedObjectsStore.getState(); // Get the current state + const zone = state.zones[zoneName]; + + if (!zone) return; + + const originalObject = zone.objects[index]; + if (!originalObject) return; + + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + // Create a shallow copy of the object with a unique ID and slightly adjusted position + const duplicatedObject: DroppedObject = { + ...originalObject, + id: `${originalObject.id}-copy-${Date.now()}`, // Unique ID + position: { + ...originalObject.position, + top: + typeof originalObject.position.top === "number" + ? originalObject.position.top + 20 // Offset vertically + : originalObject.position.top, + left: + typeof originalObject.position.left === "number" + ? originalObject.position.left + 20 // Offset horizontally + : originalObject.position.left, + }, + }; + + console.log("zone: ", zone.zoneId); + console.log("duplicatedObject: ", duplicatedObject); + + // Make async API call outside of Zustand set function + // let response = await addingFloatingWidgets( + // zone.zoneId, + // organization, + // duplicatedObject + // ); + + // if (response.message === "FloatWidget created successfully") { + // Update the state inside `set` + useDroppedObjectsStore.setState((state) => ({ + zones: { + ...state.zones, + [zoneName]: { + ...state.zones[zoneName], + objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object + }, + }, + })); + // } + }, })); export interface DroppedObjects { @@ -91,4 +160,12 @@ export interface Zones { objects: DroppedObject[]; } +export const use3DWidget = create((set: any) => ({ + widgets3D: [], + setWidgets3D: (x: any) => set({ widgets3D: x }), +})); +export const useFloatingWidget = create((set: any) => ({ + floatingWidget: [], + setFloatingWidget: (x: any) => set({ floatingWidget: x }), +})); diff --git a/app/src/store/useTemplateStore.ts b/app/src/store/useTemplateStore.ts index 2adcd2f..d416154 100644 --- a/app/src/store/useTemplateStore.ts +++ b/app/src/store/useTemplateStore.ts @@ -1,7 +1,5 @@ import { create } from "zustand"; -// type Side = "top" | "bottom" | "left" | "right"; - export interface Widget { id: string; type: string; @@ -15,21 +13,34 @@ export interface Template { name: string; panelOrder: string[]; widgets: Widget[]; - snapshot?: string | null; // Add an optional image property (base64) + floatingWidget: any[]; // Fixed empty array type + widgets3D: any[]; // Fixed empty array type + snapshot?: string | null; } interface TemplateStore { templates: Template[]; addTemplate: (template: Template) => void; + setTemplates: (templates: Template[]) => void; // Changed from `setTemplate` removeTemplate: (id: string) => void; } export const useTemplateStore = create((set) => ({ templates: [], + + // Add a new template to the list addTemplate: (template) => set((state) => ({ templates: [...state.templates, template], })), + + // Set (replace) the templates list with a new array + setTemplates: (templates) => + set(() => ({ + templates, // Ensures no duplication + })), + + // Remove a template by ID removeTemplate: (id) => set((state) => ({ templates: state.templates.filter((t) => t.id !== id), @@ -37,3 +48,4 @@ export const useTemplateStore = create((set) => ({ })); export default useTemplateStore; + diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index b080840..5df1bf7 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -543,8 +543,6 @@ color: white; } - - .floating-wrapper { .icon { width: 25px !important; @@ -612,9 +610,6 @@ .dublicate { cursor: not-allowed; } - - - } } @@ -622,12 +617,6 @@ - - - - - -/* General styles for all distance lines */ .distance-line { position: absolute; border-style: dashed; From d4e4952de4608012f441ab93727d7d47de128e57 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 31 Mar 2025 19:25:44 +0530 Subject: [PATCH 08/11] conflicts resolved --- app/src/components/ui/componets/DroppedFloatingWidgets.tsx | 3 +-- app/src/pages/Project.tsx | 2 +- .../realTimeVisulization/zoneData/addFloatingWidgets.ts | 3 +++ app/src/services/realTimeVisulization/zoneData/addWidgets.ts | 4 ++-- .../services/realTimeVisulization/zoneData/getFloatingData.ts | 4 ++-- app/src/services/realTimeVisulization/zoneData/getZoneData.ts | 4 ++-- app/src/services/realTimeVisulization/zoneData/panel.ts | 4 ++-- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 5526902..e099452 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -265,12 +265,11 @@ const DroppedObjects: React.FC = () => { animationRef.current = null; } } catch (error) { - + console.error("Error in handlePointerUp:", error); } }; const handleKebabClick = (id: string, event: React.MouseEvent) => { - event.stopPropagation(); setOpenKebabId((prevId) => (prevId === id ? null : id)); }; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index a7800e1..8e426aa 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -52,7 +52,7 @@ const Project: React.FC = () => { return (
- {loadingProgress && } + {/* {loadingProgress && } */} {!isPlaying && ( <> diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts index d73ec0d..fb644c6 100644 --- a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts @@ -6,6 +6,9 @@ export const addingFloatingWidgets = async ( organization: string, widget: {} ) => { + console.log('organization: ', organization); + console.log('widget: ', widget); + console.log('zoneId: ', zoneId); try { const response = await fetch( `${url_Backend_dwinzo}/api/v2/floatwidget/save`, diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 8539e54..08969ab 100644 --- a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts @@ -1,5 +1,5 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const addingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts index 80d2b19..0246175 100644 --- a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts @@ -1,5 +1,5 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getFloatingZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index efbac3b..f68ef15 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts @@ -1,5 +1,5 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZone2dData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts index 82f1289..6d93d1f 100644 --- a/app/src/services/realTimeVisulization/zoneData/panel.ts +++ b/app/src/services/realTimeVisulization/zoneData/panel.ts @@ -1,5 +1,5 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; type Side = "top" | "bottom" | "left" | "right"; export const panelData = async ( From e3a85c81e5c4cc4befa9f97349c6dddb0f874d87 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 31 Mar 2025 19:38:23 +0530 Subject: [PATCH 09/11] Refactor socket initialization to include organization and enhance asset event handling; remove unused console logs and improve asset data structure --- .../components/layout/sidebarLeft/Assets.tsx | 12 +- .../geomentries/assets/addAssetModel.ts | 106 ++++++++++++------ .../builder/groups/floorItemsGroup.tsx | 4 + .../collaboration/socketResponses.dev.tsx | 3 +- app/src/modules/scene/world/world.tsx | 2 +- .../simulation/behaviour/behaviour.tsx | 6 - app/src/pages/Project.tsx | 2 +- .../assest/floorAsset/setFloorItemApi.ts | 24 +++- .../services/simulation/getAssetEventType.ts | 1 - app/src/store/store.ts | 13 +-- app/src/types/world/worldConstants.ts | 26 ----- app/src/types/world/worldTypes.d.ts | 23 +++- 12 files changed, 137 insertions(+), 85 deletions(-) diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index f8733dc..2498e63 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -9,6 +9,7 @@ import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets import arch from "../../../assets/gltf-glb/arch.glb"; import door from "../../../assets/gltf-glb/door.glb"; import window from "../../../assets/gltf-glb/window.glb"; +import { useSelectedItem } from "../../../store/store"; interface AssetProp { filename: string; thumbnail?: string; @@ -23,6 +24,7 @@ interface AssetProp { CreatedBy?: String; } const Assets: React.FC = () => { + const { setSelectedItem } = useSelectedItem(); const [searchValue, setSearchValue] = useState(""); const [selectedCategory, setSelectedCategory] = useState(null); const [filteredAsset, setFilteredAsset] = useState([]); @@ -85,11 +87,11 @@ const Assets: React.FC = () => { try { const res = await getCategoryAsset(asset); setFilteredAsset(res || []); // Ensure it's always an array - } catch (error) {} + } catch (error) { } } }; - useEffect(() => {}, [filteredAsset]); + useEffect(() => { }, [filteredAsset]); return (
@@ -102,7 +104,10 @@ const Assets: React.FC = () => { {/* Back Button */}
setSelectedCategory(null)} + onClick={() => { + setSelectedCategory(null); + setFilteredAsset([]); + }} > ← Back
@@ -116,6 +121,7 @@ const Assets: React.FC = () => { src={asset?.thumbnail} alt={asset.filename} className="asset-image" + onPointerDown={() => setSelectedItem({ name: asset.filename, id: asset.modelfileID })} /> )}
diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index e0e50c6..65832f8 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -9,6 +9,8 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { Socket } from 'socket.io-client'; import * as CONSTANTS from '../../../../types/world/worldConstants'; +import { getAssetEventType } from '../../../../services/simulation/getAssetEventType'; +import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; async function addAssetModel( raycaster: THREE.Raycaster, @@ -58,6 +60,7 @@ async function addAssetModel( if (intersectPoint.y < 0) { intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); } + console.log('selectedItem: ', selectedItem); const cachedModel = THREE.Cache.get(selectedItem.id); if (cachedModel) { // console.log(`[Cache] Fetching ${selectedItem.name}`); @@ -136,51 +139,88 @@ async function handleModelLoad( modelname: selectedItem.name, modelfileID: selectedItem.id, position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, }, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, isLocked: false, isVisible: true }; - setFloorItems((prevItems) => { - const updatedItems = [...(prevItems || []), newFloorItem]; - localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); - return updatedItems; - }); - const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; - //REST + getAssetEventType(selectedItem.id, organization).then(async (res) => { + console.log('res: ', res); - // await setFloorItemApi( - // organization, - // newFloorItem.modeluuid, - // newFloorItem.modelname, - // newFloorItem.position, - // { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z }, - // newFloorItem.modelfileID!, - // false, - // true, - // ); + if (res.type === "Conveyor") { + const pointUUIDs = res.points.map(() => THREE.MathUtils.generateUUID()); - //SOCKET + const eventData: Extract = { + type: 'Conveyor', + points: res.points.map((point: any, index: number) => ({ + uuid: pointUUIDs[index], + position: point.position as [number, number, number], + rotation: point.rotation as [number, number, number], + actions: [{ + uuid: THREE.MathUtils.generateUUID(), + name: 'Action 1', + type: 'Inherit', + material: 'Inherit', + delay: 'Inherit', + spawnInterval: 'Inherit', + isUsed: false + }], + triggers: [], + connections: { + source: { pathUUID: model.uuid, pointUUID: pointUUIDs[index] }, + targets: [] + } + })), + speed: 'Inherit' + }; - const data = { - organization, - modeluuid: newFloorItem.modeluuid, - modelname: newFloorItem.modelname, - modelfileID: newFloorItem.modelfileID, - position: newFloorItem.position, - rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, - isLocked: false, - isVisible: true, - socketId: socket.id, - }; + console.log('eventData: ', eventData); + newFloorItem.eventData = eventData; + } - socket.emit("v1:FloorItems:set", data); + setFloorItems((prevItems) => { + const updatedItems = [...(prevItems || []), newFloorItem]; + localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); + return updatedItems; + }); - gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); - gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); + // API + + // await setFloorItemApi( + // organization, + // newFloorItem.modeluuid, + // newFloorItem.modelname, + // newFloorItem.modelfileID, + // newFloorItem.position, + // { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + // false, + // true, + // newFloorItem.eventData + // ); + + // SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, + isLocked: false, + isVisible: true, + eventData: newFloorItem.eventData, + socketId: socket.id + }; + + socket.emit("v2:model-asset:add", data); + + gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); + gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); + }); } export default addAssetModel; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index cf9d6b8..3b38d01 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -60,6 +60,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject }; getFloorItems(organization).then((data) => { + console.log('data: ', data); const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID) ); @@ -305,7 +306,10 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject }; }, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule]); + useEffect(() => { + console.log('floorItems: ', floorItems); + }, [floorItems]) useFrame(() => { if (controls) diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index 031629f..1a5ef83 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -81,7 +81,8 @@ export default function SocketResponses({ // console.log('data: ', data); }) - socket.on('FloorItemsUpdateResponse', async (data: any) => { + socket.on('model-asset:response:updates', async (data: any) => { + console.log('data: ', data); if (socket.id === data.socketId) { return } diff --git a/app/src/modules/scene/world/world.tsx b/app/src/modules/scene/world/world.tsx index eb7d555..76cf539 100644 --- a/app/src/modules/scene/world/world.tsx +++ b/app/src/modules/scene/world/world.tsx @@ -358,7 +358,7 @@ export default function World() { anglesnappedPoint={anglesnappedPoint} /> - + {/* */} diff --git a/app/src/modules/simulation/behaviour/behaviour.tsx b/app/src/modules/simulation/behaviour/behaviour.tsx index afb4ae9..5075384 100644 --- a/app/src/modules/simulation/behaviour/behaviour.tsx +++ b/app/src/modules/simulation/behaviour/behaviour.tsx @@ -2,22 +2,16 @@ import { useFloorItems, useSimulationPaths } from '../../../store/store'; import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; import { useEffect } from 'react'; -import { getAssetEventType } from '../../../services/simulation/getAssetEventType'; function Behaviour() { const { setSimulationPaths } = useSimulationPaths(); const { floorItems } = useFloorItems(); useEffect(() => { - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; const newPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] = []; floorItems.forEach((item: Types.FloorItemType) => { if (item.modelfileID === "672a090f80d91ac979f4d0bd") { - // getAssetEventType(item.modelfileID, organization).then((res) => { - // console.log('res: ', res); - // }); const point1Position = new THREE.Vector3(0, 0.85, 2.2); const middlePointPosition = new THREE.Vector3(0, 0.85, 0); const point2Position = new THREE.Vector3(0, 0.85, -2.2); diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 41f04a7..7aad5cb 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -37,8 +37,8 @@ const Project: React.FC = () => { setZones([]); const email = localStorage.getItem("email"); if (email) { - useSocketStore.getState().initializeSocket(email); const Organization = email!.split("@")[1].split(".")[0]; + useSocketStore.getState().initializeSocket(email, Organization); const name = localStorage.getItem("userName"); if (Organization && name) { setOrganization(Organization); diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts index 31d5b11..f6cd496 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts @@ -1,13 +1,28 @@ -let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_TEST}`; -export const setFloorItemApi = async (organization: string, modeluuid: string, modelname: string, position: Object, rotation: Object, modelfileID: string, isLocked: boolean, isVisible: boolean) => { +export const setFloorItemApi = async ( + organization: string, + modeluuid: string, + modelname: string, + modelfileID: string, + position: Object, + rotation: Object, + isLocked: boolean, + isVisible: boolean, + eventData?: any +) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setFloorItems`, { + const body: any = { organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible }; + if (eventData) { + body.eventData = eventData; + } + + const response = await fetch(`${url_Backend_dwinzo}/api/v2/setasset`, { method: "POST", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, modeluuid, modelname, position, rotation, modelfileID, isLocked, isVisible }), + body: JSON.stringify(body), }); if (!response.ok) { @@ -15,6 +30,7 @@ export const setFloorItemApi = async (organization: string, modeluuid: string, m } const result = await response.json(); + console.log('result: ', result); return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/simulation/getAssetEventType.ts b/app/src/services/simulation/getAssetEventType.ts index e516feb..a681b12 100644 --- a/app/src/services/simulation/getAssetEventType.ts +++ b/app/src/services/simulation/getAssetEventType.ts @@ -14,7 +14,6 @@ export const getAssetEventType = async (modelId: string, organization: string) = } const result = await response.json(); - console.log('result: ', result); return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 9688448..964a1a7 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -5,19 +5,16 @@ import { io } from "socket.io-client"; export const useSocketStore = create((set: any, get: any) => ({ socket: null, - initializeSocket: (email: any) => { + initializeSocket: (email: string, organization: string) => { const existingSocket = get().socket; if (existingSocket) { return; } - const socket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/`, - { - reconnection: false, - auth: { email }, - } - ); + const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { + reconnection: false, + auth: { email, organization }, + }); set({ socket }); }, diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 66743fb..c9f187b 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -61,7 +61,6 @@ export type GridConfig = { divisions: number; primaryColor: string; secondaryColor: string; - position2D: [x: number, y: number, z: number]; position3D: [x: number, y: number, z: number]; }; @@ -70,7 +69,6 @@ export type PlaneConfig = { position2D: [x: number, y: number, z: number]; position3D: [x: number, y: number, z: number]; rotation: number; - width: number; height: number; color: string; @@ -78,7 +76,6 @@ export type PlaneConfig = { export type ShadowConfig = { shadowOffset: number; - shadowmapSizewidth: number; shadowmapSizeheight: number; shadowcamerafar: number; @@ -89,10 +86,8 @@ export type ShadowConfig = { shadowcameraright: number; shadowbias: number; shadownormalBias: number; - shadowMaterialPosition: [x: number, y: number, z: number]; shadowMaterialRotation: [x: number, y: number, z: number]; - shadowMaterialOpacity: number; }; @@ -116,12 +111,10 @@ export type PointConfig = { defaultOuterColor: string; deleteColor: string; boxScale: [number, number, number]; - wallOuterColor: string; floorOuterColor: string; aisleOuterColor: string; zoneOuterColor: string; - snappingThreshold: number; }; @@ -129,17 +122,13 @@ export type LineConfig = { tubularSegments: number; radius: number; radialSegments: number; - wallName: string; floorName: string; aisleName: string; zoneName: string; referenceName: string; - lineIntersectionPoints: number; - defaultColor: string; - wallColor: string; floorColor: string; aisleColor: string; @@ -156,7 +145,6 @@ export type WallConfig = { export type FloorConfig = { defaultColor: string; height: number; - textureScale: number; }; @@ -168,13 +156,11 @@ export type RoofConfig = { export type AisleConfig = { width: number; height: number; - defaultColor: number; }; export type ZoneConfig = { defaultColor: string; - color: string; }; @@ -199,9 +185,7 @@ export const firstPersonControls: Controls = { minDistance: 0, // Minimum distance from the target maxDistance: 0, // Maximum distance from the target maxPolarAngle: Math.PI, // Maximum polar angle - leftMouse: 1, // Mouse button for rotation (ROTATE) - forwardSpeed: 0.3, // Speed of forward movement backwardSpeed: -0.3, // Speed of backward movement leftSpeed: -0.3, // Speed of left movement @@ -259,7 +243,6 @@ export const gridConfig: GridConfig = { divisions: 75, // Number of divisions in the grid primaryColor: "#d5d5d5", // Primary color of the grid secondaryColor: "#e3e3e3", // Secondary color of the grid - position2D: [0, 0.1, 0], // Position of the grid in 2D view position3D: [0, -0.5, 0], // Position of the grid in 3D view }; @@ -276,7 +259,6 @@ export const planeConfig: PlaneConfig = { export const shadowConfig: ShadowConfig = { shadowOffset: 50, // Offset of the shadow - shadowmapSizewidth: 1024, // Width of the shadow map shadowmapSizeheight: 1024, // Height of the shadow map // shadowmapSizewidth: 8192, // Width of the shadow map @@ -289,10 +271,8 @@ export const shadowConfig: ShadowConfig = { shadowcameraright: 30, // Right plane of the shadow camera shadowbias: -0.001, // Bias of the shadow shadownormalBias: 0.02, // Normal bias of the shadow - shadowMaterialPosition: [0, 0.01, 0], // Position of the shadow material shadowMaterialRotation: [-Math.PI / 2, 0, 0], // Rotation of the shadow material - shadowMaterialOpacity: 0.1, // Opacity of the shadow material }; @@ -316,12 +296,10 @@ export const pointConfig: PointConfig = { defaultOuterColor: "#ffffff", // Default outer color of the points deleteColor: "#ff0000", // Color of the points when deleting boxScale: [0.5, 0.5, 0.5], // Scale of the points - wallOuterColor: "#C7C7C7", // Outer color of the wall points floorOuterColor: "#808080", // Outer color of the floor points aisleOuterColor: "#FBBC05", // Outer color of the aisle points zoneOuterColor: "#007BFF", // Outer color of the zone points - snappingThreshold: 1, // Threshold for snapping }; @@ -329,17 +307,13 @@ export const lineConfig: LineConfig = { tubularSegments: 64, // Number of tubular segments radius: 0.15, // Radius of the lines radialSegments: 8, // Number of radial segments - wallName: "WallLine", // Name of the wall lines floorName: "FloorLine", // Name of the floor lines aisleName: "AisleLine", // Name of the aisle lines zoneName: "ZoneLine", // Name of the zone lines referenceName: "ReferenceLine", // Name of the reference lines - lineIntersectionPoints: 300, // Number of intersection points - defaultColor: "#000000", // Default color of the lines - wallColor: "#C7C7C7", // Color of the wall lines floorColor: "#808080", // Color of the floor lines aisleColor: "#FBBC05", // Color of the aisle lines diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 3e40f40..4d10a36 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -198,9 +198,30 @@ export type FloorItemType = { modelname: string; position: [number, number, number]; rotation: { x: number; y: number; z: number }; - modelfileID?: string; + modelfileID: string; isLocked: boolean; isVisible: boolean; + eventData?: { + type: 'Conveyor'; + points: { + uuid: string; + position: [number, number, number]; + rotation: [number, number, number]; + actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; + triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | []; + connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + }[]; + speed: number | string; + } | { + type: 'Vehicle'; + point: { + uuid: string; + position: [number, number, number]; + actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; + connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] }; + speed: number; + }; + }; }; // Array of floor items for managing multiple objects on the floor From f78b7ce6c5785fcd0b48e02506fe4fb5c98c558d Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Mon, 31 Mar 2025 19:39:09 +0530 Subject: [PATCH 10/11] conflicts resolved in api file --- app/src/components/ui/componets/Dropped3dWidget.tsx | 1 - app/src/components/ui/componets/RealTimeVisulization.tsx | 3 +++ app/src/pages/Project.tsx | 2 +- app/src/services/realTimeVisulization/zoneData/addWidgets.ts | 4 ++-- .../services/realTimeVisulization/zoneData/getFloatingData.ts | 4 ++-- app/src/services/realTimeVisulization/zoneData/getZoneData.ts | 4 ++-- app/src/services/realTimeVisulization/zoneData/panel.ts | 4 ++-- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index c627af4..94c5e45 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -26,7 +26,6 @@ export default function Dropped3dWidgets() { Record >({}); const { setWidgets3D } = use3DWidget() - useEffect(() => { if (activeModule !== "visualization") return if (selectedZone.zoneName === "") return; diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 3f81518..f6a041a 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -63,6 +63,7 @@ const RealTimeVisulization: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; try { const response = await getZone2dData(organization); + console.log('response: ', response); if (!Array.isArray(response)) { return; @@ -152,6 +153,7 @@ const RealTimeVisulization: React.FC = () => { .getState() .setZone(selectedZone.zoneName, selectedZone.zoneId); } + // Add the dropped object to the zone if the API call is successful if (response.message === "FloatWidget created successfully") { useDroppedObjectsStore @@ -200,6 +202,7 @@ const RealTimeVisulization: React.FC = () => {
{activeModule === "visualization" && selectedZone.zoneName !== "" && } + {/* */} {activeModule === "visualization" && ( <> { return (
- {/* {loadingProgress && } */} + {loadingProgress && } {!isPlaying && ( <> diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 08969ab..8539e54 100644 --- a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts @@ -1,5 +1,5 @@ -// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -let url_Backend_dwinzo = `http://192.168.0.102:5000`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const addingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts index 0246175..80d2b19 100644 --- a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts @@ -1,5 +1,5 @@ -// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -let url_Backend_dwinzo = `http://192.168.0.102:5000`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getFloatingZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index f68ef15..efbac3b 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts @@ -1,5 +1,5 @@ -// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -let url_Backend_dwinzo = `http://192.168.0.102:5000`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZone2dData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts index 6d93d1f..82f1289 100644 --- a/app/src/services/realTimeVisulization/zoneData/panel.ts +++ b/app/src/services/realTimeVisulization/zoneData/panel.ts @@ -1,5 +1,5 @@ -// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -let url_Backend_dwinzo = `http://192.168.0.102:5000`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; type Side = "top" | "bottom" | "left" | "right"; export const panelData = async ( From 945fc0396f24f04cad024ee8d7de8f388e42397c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Mon, 31 Mar 2025 19:54:21 +0530 Subject: [PATCH 11/11] No code changes detected; skipping commit. --- .../ui/componets/DroppedFloatingWidgets.tsx | 694 +++++++++--------- 1 file changed, 339 insertions(+), 355 deletions(-) diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 4f2deb5..d7a6960 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -56,113 +56,159 @@ const DroppedObjects: React.FC = () => { ); const [offset, setOffset] = useState<[number, number] | null>(null); const { setSelectedChartId } = useWidgetStore(); - const positionRef = useRef<[number, number] | null>(null); + const [activeEdges, setActiveEdges] = useState<{ + vertical: "top" | "bottom"; + horizontal: "left" | "right"; + } | null>(null); // State to track active edges for distance lines + const [currentPosition, setCurrentPosition] = useState<{ + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + } | null>(null); // State to track the current position during drag const animationRef = useRef(null); const { activeModule } = useModuleStore(); - // Get the first zone and its objects + // Clean up animation frame on unmount + useEffect(() => { + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + }; + }, []); + const zoneEntries = Object.entries(zones); - if (zoneEntries.length === 0) return null; // No zone, nothing to render - const [zoneName, zone] = zoneEntries[0]; // Only render the first zone - console.log("zone", zone); + if (zoneEntries.length === 0) return null; + const [zoneName, zone] = zoneEntries[0]; + + function handleDuplicate(zoneName: string, index: number) { + setOpenKebabId(null) + duplicateObject(zoneName, index); // Call the duplicateObject method from the store + } + + async function handleDelete(zoneName: string, id: string, index: number) { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + let res = await deleteFloatingWidgetApi(id, organization); + console.log('res: ', res); + + if (res.message === "FloatingWidget deleted successfully") { + deleteObject(zoneName, index); // Call the deleteObject method from the store + } + } catch (error) { + console.error("Error deleting floating widget:", error); + } + } + const handlePointerDown = (event: React.PointerEvent, index: number) => { + const obj = zone.objects[index]; + const container = document.getElementById("real-time-vis-canvas"); + if (!container) return; - // Handle pointer down event - function handlePointerDown(event: React.PointerEvent, index: number) { + const rect = container.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; - const [activeEdges, setActiveEdges] = useState<{ - vertical: "top" | "bottom"; - horizontal: "left" | "right"; - } | null>(null); // State to track active edges for distance lines - const [currentPosition, setCurrentPosition] = useState<{ - top: number | "auto"; - left: number | "auto"; - right: number | "auto"; - bottom: number | "auto"; - } | null>(null); // State to track the current position during drag - const animationRef = useRef(null); - const { activeModule } = useModuleStore(); + // Determine active properties for the initial position + const [activeProp1, activeProp2] = getActiveProperties(obj.position); - // Clean up animation frame on unmount - useEffect(() => { - return () => { - if (animationRef.current) { - cancelAnimationFrame(animationRef.current); - } - }; - }, []); + // Set active edges for distance lines + const vertical = activeProp1 === "top" ? "top" : "bottom"; + const horizontal = activeProp2 === "left" ? "left" : "right"; + setActiveEdges({ vertical, horizontal }); - const zoneEntries = Object.entries(zones); - if (zoneEntries.length === 0) return null; - const [zoneName, zone] = zoneEntries[0]; + // Store the initial position strategy and active edges + setDraggingIndex({ + zone: zoneName, + index, + initialPosition: { ...obj.position }, + }); - function handleDuplicate(zoneName: string, index: number) { - setOpenKebabId(null) - duplicateObject(zoneName, index); // Call the duplicateObject method from the store + // Calculate offset from mouse to object edges + let offsetX = 0; + let offsetY = 0; + + if (activeProp1 === "top") { + offsetY = relativeY - (obj.position.top as number); + } else { + offsetY = rect.height - relativeY - (obj.position.bottom as number); } - async function handleDelete(zoneName: string, id: string, index: number) { - try { - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; - - let res = await deleteFloatingWidgetApi(id, organization); - console.log('res: ', res); - - if (res.message === "FloatingWidget deleted successfully") { - deleteObject(zoneName, index); // Call the deleteObject method from the store - } - } catch (error) { - console.error("Error deleting floating widget:", error); - } + if (activeProp2 === "left") { + offsetX = relativeX - (obj.position.left as number); + } else { + offsetX = rect.width - relativeX - (obj.position.right as number); } + setOffset([offsetY, offsetX]); + }; - const handlePointerDown = (event: React.PointerEvent, index: number) => { - const obj = zone.objects[index]; - const container = document.getElementById("real-time-vis-canvas"); - if (!container) return; + const handlePointerMove = (event: React.PointerEvent) => { + if (!draggingIndex || !offset) return; - const rect = container.getBoundingClientRect(); - const relativeX = event.clientX - rect.left; - const relativeY = event.clientY - rect.top; + const container = document.getElementById("real-time-vis-canvas"); + if (!container) return; - // Determine active properties for the initial position - const [activeProp1, activeProp2] = getActiveProperties(obj.position); + const rect = container.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; - // Set active edges for distance lines - const vertical = activeProp1 === "top" ? "top" : "bottom"; - const horizontal = activeProp2 === "left" ? "left" : "right"; - setActiveEdges({ vertical, horizontal }); + // Dynamically determine the current position strategy + const newPositionStrategy = determinePosition(rect, relativeX, relativeY); + const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy); - // Store the initial position strategy and active edges - setDraggingIndex({ - zone: zoneName, - index, - initialPosition: { ...obj.position }, - }); + // Update active edges for distance lines + const vertical = activeProp1 === "top" ? "top" : "bottom"; + const horizontal = activeProp2 === "left" ? "left" : "right"; + setActiveEdges({ vertical, horizontal }); - // Calculate offset from mouse to object edges - let offsetX = 0; - let offsetY = 0; + // Calculate new position based on the active properties + let newY = 0; + let newX = 0; - if (activeProp1 === "top") { - offsetY = relativeY - (obj.position.top as number); - } else { - offsetY = rect.height - relativeY - (obj.position.bottom as number); - } + if (activeProp1 === "top") { + newY = relativeY - offset[0]; + } else { + newY = rect.height - (relativeY + offset[0]); + } - if (activeProp2 === "left") { - offsetX = relativeX - (obj.position.left as number); - } else { - offsetX = rect.width - relativeX - (obj.position.right as number); - } + if (activeProp2 === "left") { + newX = relativeX - offset[1]; + } else { + newX = rect.width - (relativeX + offset[1]); + } - setOffset([offsetY, offsetX]); + // Apply boundaries + newX = Math.max(0, Math.min(rect.width - 50, newX)); + newY = Math.max(0, Math.min(rect.height - 50, newY)); + + // Create new position object + const newPosition = { + ...newPositionStrategy, + [activeProp1]: newY, + [activeProp2]: newX, + // Clear opposite properties + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", }; - const handlePointerMove = (event: React.PointerEvent) => { + // Update the current position state for DistanceLines + setCurrentPosition(newPosition); + + if (!animationRef.current) { + animationRef.current = requestAnimationFrame(() => { + updateObjectPosition(zoneName, draggingIndex.index, newPosition); + animationRef.current = null; + }); + } + }; + + const handlePointerUp = async (event: React.PointerEvent) => { + try { if (!draggingIndex || !offset) return; const container = document.getElementById("real-time-vis-canvas"); @@ -172,299 +218,237 @@ const DroppedObjects: React.FC = () => { const relativeX = event.clientX - rect.left; const relativeY = event.clientY - rect.top; - // Dynamically determine the current position strategy - const newPositionStrategy = determinePosition(rect, relativeX, relativeY); - const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy); + // Only now determine the final position strategy + const finalPosition = determinePosition(rect, relativeX, relativeY); + const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - // Update active edges for distance lines - const vertical = activeProp1 === "top" ? "top" : "bottom"; - const horizontal = activeProp2 === "left" ? "left" : "right"; - setActiveEdges({ vertical, horizontal }); - - // Calculate new position based on the active properties - let newY = 0; - let newX = 0; + // Calculate final position using the new strategy + let finalY = 0; + let finalX = 0; if (activeProp1 === "top") { - newY = relativeY - offset[0]; + finalY = relativeY - offset[0]; } else { - newY = rect.height - (relativeY + offset[0]); + finalY = rect.height - (relativeY + offset[0]); } if (activeProp2 === "left") { - newX = relativeX - offset[1]; + finalX = relativeX - offset[1]; } else { - newX = rect.width - (relativeX + offset[1]); + finalX = rect.width - (relativeX + offset[1]); } // Apply boundaries - newX = Math.max(0, Math.min(rect.width - 50, newX)); - newY = Math.max(0, Math.min(rect.height - 50, newY)); + finalX = Math.max(0, Math.min(rect.width - 50, finalX)); + finalY = Math.max(0, Math.min(rect.height - 50, finalY)); - // Create new position object - const newPosition = { - ...newPositionStrategy, - [activeProp1]: newY, - [activeProp2]: newX, - // Clear opposite properties - [activeProp1 === "top" ? "bottom" : "top"]: "auto", - [activeProp2 === "left" ? "right" : "left"]: "auto", + const boundedPosition = { + ...finalPosition, + [activeProp1]: finalY, + [activeProp2]: finalX, }; - // Update the current position state for DistanceLines - setCurrentPosition(newPosition); + // Save to backend + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const response = await addingFloatingWidgets(zone.zoneId, organization, { + ...zone.objects[draggingIndex.index], + position: boundedPosition, + }); - if (!animationRef.current) { - animationRef.current = requestAnimationFrame(() => { - updateObjectPosition(zoneName, draggingIndex.index, newPosition); - animationRef.current = null; - }); + if (response.message === "Widget updated successfully") { + updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); } - }; - const handlePointerUp = async (event: React.PointerEvent) => { - try { - if (!draggingIndex || !offset) return; - - const container = document.getElementById("real-time-vis-canvas"); - if (!container) return; - - const rect = container.getBoundingClientRect(); - const relativeX = event.clientX - rect.left; - const relativeY = event.clientY - rect.top; - - // Only now determine the final position strategy - const finalPosition = determinePosition(rect, relativeX, relativeY); - const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - - // Calculate final position using the new strategy - let finalY = 0; - let finalX = 0; - - if (activeProp1 === "top") { - finalY = relativeY - offset[0]; - } else { - finalY = rect.height - (relativeY + offset[0]); - } - - if (activeProp2 === "left") { - finalX = relativeX - offset[1]; - } else { - finalX = rect.width - (relativeX + offset[1]); - } - - // Apply boundaries - finalX = Math.max(0, Math.min(rect.width - 50, finalX)); - finalY = Math.max(0, Math.min(rect.height - 50, finalY)); - - const boundedPosition = { - ...finalPosition, - [activeProp1]: finalY, - [activeProp2]: finalX, - }; - - // Save to backend - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; - const response = await addingFloatingWidgets(zone.zoneId, organization, { - ...zone.objects[draggingIndex.index], - position: boundedPosition, - }); - - if (response.message === "Widget updated successfully") { - updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); - } - - // Clean up - setDraggingIndex(null); - setOffset(null); - setActiveEdges(null); // Clear active edges - setCurrentPosition(null); // Reset current position - if (animationRef.current) { - cancelAnimationFrame(animationRef.current); - animationRef.current = null; - } - } catch (error) { - console.error("Error in handlePointerUp:", error); + // Clean up + setDraggingIndex(null); + setOffset(null); + setActiveEdges(null); // Clear active edges + setCurrentPosition(null); // Reset current position + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + animationRef.current = null; } - }; - - const handleKebabClick = (id: string, event: React.MouseEvent) => { - event.stopPropagation(); - setOpenKebabId((prevId) => (prevId === id ? null : id)); - }; - - const renderObjectContent = (obj: any) => { - switch (obj.className) { - case "floating total-card": - return ( - <> -
-
{obj.header}
-
-
{obj.value}
-
{obj.per}
-
-
-
- -
- - ); - case "warehouseThroughput floating": - return ( - <> -
-

Warehouse Throughput

-

- (+5) more in 2025 -

-
-
- {/* */} -
- - ); - case "fleetEfficiency floating": - return ( - <> -

Fleet Efficiency

-
-
-
-
-
-
-
-
- 0% -
-
{obj.per}%
-
Optimal
-
- 100% -
- - ); - default: - return null; - } - }; - - return ( -
- {zone.objects.map((obj, index) => ( -
handlePointerDown(event, index)} - onClick={() => { - setSelectedChartId(obj) - }} - > - {obj.className === "floating total-card" ? ( - <> - - - ) : obj.className === "warehouseThroughput floating" ? ( - <> - - - ) : obj.className === "fleetEfficiency floating" ? ( - <> - - - ) : null} - {renderObjectContent(obj)} -
handleKebabClick(obj.id, event)} - > - -
- {openKebabId === obj.id && ( -
-
{ - event.stopPropagation(); - handleDuplicate(zoneName, index); // Call the duplicate handler - }}> -
- -
-
Duplicate
-
-
{ - event.stopPropagation(); - handleDelete(zoneName, obj.id, index); // Call the delete handler - }}> -
- -
-
Delete
-
-
- )} -
- ))} - - {/* Render DistanceLines component during drag */} - {draggingIndex !== null && - activeEdges !== null && - currentPosition !== null && ( - - )} -
- ); + } catch (error) { + console.error("Error in handlePointerUp:", error); + } }; -} + + const handleKebabClick = (id: string, event: React.MouseEvent) => { + event.stopPropagation(); + setOpenKebabId((prevId) => (prevId === id ? null : id)); + }; + + const renderObjectContent = (obj: any) => { + switch (obj.className) { + case "floating total-card": + return ( + <> +
+
{obj.header}
+
+
{obj.value}
+
{obj.per}
+
+
+
+ +
+ + ); + case "warehouseThroughput floating": + return ( + <> +
+

Warehouse Throughput

+

+ (+5) more in 2025 +

+
+
+ {/* */} +
+ + ); + case "fleetEfficiency floating": + return ( + <> +

Fleet Efficiency

+
+
+
+
+
+
+
+
+ 0% +
+
{obj.per}%
+
Optimal
+
+ 100% +
+ + ); + default: + return null; + } + }; + + return ( +
+ {zone.objects.map((obj, index) => ( +
handlePointerDown(event, index)} + onClick={() => { + setSelectedChartId(obj) + }} + > + {obj.className === "floating total-card" ? ( + <> + + + ) : obj.className === "warehouseThroughput floating" ? ( + <> + + + ) : obj.className === "fleetEfficiency floating" ? ( + <> + + + ) : null} + {renderObjectContent(obj)} +
handleKebabClick(obj.id, event)} + > + +
+ {openKebabId === obj.id && ( +
+
{ + event.stopPropagation(); + handleDuplicate(zoneName, index); // Call the duplicate handler + }}> +
+ +
+
Duplicate
+
+
{ + event.stopPropagation(); + handleDelete(zoneName, obj.id, index); // Call the delete handler + }}> +
+ +
+
Delete
+
+
+ )} +
+ ))} + + {/* Render DistanceLines component during drag */} + {draggingIndex !== null && + activeEdges !== null && + currentPosition !== null && ( + + )} +
+ ); +}; export default DroppedObjects;