diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index abeca05..2370d8c 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -49,25 +49,22 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > @@ -78,7 +75,18 @@ const SideBarRight: React.FC = () => { )} {/* process builder */} {toggleUI && - activeList === "properties" && + subModule === "zoneProperties" && + activeModule === "builder" && ( +
+
+ {/* */} + + {/* */} +
+
+ )} + {toggleUI && + subModule === "properties" && activeModule !== "visualization" && (
@@ -88,7 +96,6 @@ const SideBarRight: React.FC = () => {
)} - {/* simulation */} {toggleUI && activeModule === "simulation" && ( diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 65dd55f..4baf91c 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -1,9 +1,11 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; +import { useSelectedZoneStore } from "../../../../store/useZoneStore"; const ZoneProperties: React.FC = () => { const [Edit, setEdit] = useState(false); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); function handleSetView() { setEdit(false); @@ -16,17 +18,21 @@ const ZoneProperties: React.FC = () => { setEdit(true); } } + useEffect(() => { + + console.log(' selectedZone.zoneName: ', selectedZone.zoneName); + }, [selectedZone]) return (
- +
{Edit ? "Cancel" : "Edit"}
- {}} header="Viewport Target" /> - {}} header="Viewport Position" /> + { }} header="Viewport Target" /> + { }} header="Viewport Position" /> {Edit && (
Set View diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 77baa13..cef407f 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -1,193 +1,212 @@ -import React from "react"; -import { - CleanPannel, - EyeIcon, - LockIcon, -} from "../../icons/RealTimeVisulationIcons"; - -// Define the type for `Side` -type Side = "top" | "bottom" | "left" | "right"; - -// Define the type for the props passed to the Buttons component -interface ButtonsProps { - selectedZone: { - zoneName: string; - activeSides: Side[]; - panelOrder: Side[]; - lockedPanels: Side[]; - widgets: { - id: string; - type: string; - title: string; - panel: Side; - data: any; - }[]; - }; - setSelectedZone: React.Dispatch< - React.SetStateAction<{ - zoneName: string; - activeSides: Side[]; - panelOrder: Side[]; - lockedPanels: Side[]; - widgets: { - id: string; - type: string; - title: string; - panel: Side; - data: any; - }[]; - }> - >; - hiddenPanels: Side[]; // Add this prop for hidden panels - setHiddenPanels: React.Dispatch>; // Add this prop for updating hidden panels -} - -const AddButtons: React.FC = ({ - selectedZone, - setSelectedZone, - setHiddenPanels, - hiddenPanels, -}) => { - // Local state to track hidden panels - - // Function to toggle lock/unlock a panel - const toggleLockPanel = (side: Side) => { - const newLockedPanels = selectedZone.lockedPanels.includes(side) - ? selectedZone.lockedPanels.filter((panel) => panel !== side) - : [...selectedZone.lockedPanels, side]; - - const updatedZone = { - ...selectedZone, - lockedPanels: newLockedPanels, - }; - - // Update the selectedZone state - setSelectedZone(updatedZone); - }; - - // Function to toggle visibility of a panel - const toggleVisibility = (side: Side) => { - const isHidden = hiddenPanels.includes(side); - if (isHidden) { - // If the panel is already hidden, remove it from the hiddenPanels array - setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); - } else { - // If the panel is visible, add it to the hiddenPanels array - setHiddenPanels([...hiddenPanels, side]); - } - }; - - // Function to clean all widgets from a panel - const cleanPanel = (side: Side) => { - const cleanedWidgets = selectedZone.widgets.filter( - (widget) => widget.panel !== side - ); - - const updatedZone = { - ...selectedZone, - widgets: cleanedWidgets, - }; - - // Update the selectedZone state - setSelectedZone(updatedZone); - }; - - // Function to handle "+" button click - const handlePlusButtonClick = (side: Side) => { - if (selectedZone.activeSides.includes(side)) { - // If the panel is already active, remove all widgets and close the panel - const cleanedWidgets = selectedZone.widgets.filter( - (widget) => widget.panel !== side - ); - const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); - - const updatedZone = { - ...selectedZone, - widgets: cleanedWidgets, - activeSides: newActiveSides, - panelOrder: newActiveSides, - }; - - // Update the selectedZone state - console.log('updatedZone: ', updatedZone); - setSelectedZone(updatedZone); - } else { - // If the panel is not active, activate it - const newActiveSides = [...selectedZone.activeSides, side]; - - const updatedZone = { - ...selectedZone, - activeSides: newActiveSides, - panelOrder: newActiveSides, - }; - - // Update the selectedZone state - console.log('updatedZone: ', updatedZone); - setSelectedZone(updatedZone); - } - }; - - return ( -
- {(["top", "right", "bottom", "left"] as Side[]).map((side) => ( -
- - - {/* Extra Buttons */} - {selectedZone.activeSides.includes(side) && ( -
- {/* Hide Panel */} -
toggleVisibility(side)} - > - -
- - {/* Clean Panel */} -
cleanPanel(side)} - > - -
- - {/* Lock/Unlock Panel */} -
toggleLockPanel(side)} - > - -
-
- )} -
- ))} -
- ); -}; - -export default AddButtons; +import React from "react"; +import { + CleanPannel, + EyeIcon, + LockIcon, +} from "../../icons/RealTimeVisulationIcons"; +import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; + +// Define the type for `Side` +type Side = "top" | "bottom" | "left" | "right"; + +// Define the type for the props passed to the Buttons component +interface ButtonsProps { + selectedZone: { + zoneName: string; + activeSides: Side[]; + panelOrder: Side[]; + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] + widgets: { + id: string; + type: string; + title: string; + panel: Side; + data: any; + }[]; + }; + setSelectedZone: React.Dispatch< + React.SetStateAction<{ + zoneName: string; + activeSides: Side[]; + panelOrder: Side[]; + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] + widgets: { + id: string; + type: string; + title: string; + panel: Side; + data: any; + }[]; + }> + >; + hiddenPanels: Side[]; // Add this prop for hidden panels + setHiddenPanels: React.Dispatch>; // Add this prop for updating hidden panels +} + +const AddButtons: React.FC = ({ + selectedZone, + setSelectedZone, + setHiddenPanels, + hiddenPanels, +}) => { + // Local state to track hidden panels + + // Function to toggle lock/unlock a panel + const toggleLockPanel = (side: Side) => { + const newLockedPanels = selectedZone.lockedPanels.includes(side) + ? selectedZone.lockedPanels.filter((panel) => panel !== side) + : [...selectedZone.lockedPanels, side]; + + const updatedZone = { + ...selectedZone, + lockedPanels: newLockedPanels, + }; + + // Update the selectedZone state + setSelectedZone(updatedZone); + }; + + // Function to toggle visibility of a panel + const toggleVisibility = (side: Side) => { + const isHidden = hiddenPanels.includes(side); + if (isHidden) { + // If the panel is already hidden, remove it from the hiddenPanels array + setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); + } else { + // If the panel is visible, add it to the hiddenPanels array + setHiddenPanels([...hiddenPanels, side]); + } + }; + + // Function to clean all widgets from a panel + const cleanPanel = (side: Side) => { + const cleanedWidgets = selectedZone.widgets.filter( + (widget) => widget.panel !== side + ); + + const updatedZone = { + ...selectedZone, + widgets: cleanedWidgets, + }; + + // Update the selectedZone state + setSelectedZone(updatedZone); + }; + + // Function to handle "+" button click + const handlePlusButtonClick = (side: Side) => { + if (selectedZone.activeSides.includes(side)) { + // If the panel is already active, remove all widgets and close the panel + const cleanedWidgets = selectedZone.widgets.filter( + (widget) => widget.panel !== side + ); + const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); + + const updatedZone = { + ...selectedZone, + widgets: cleanedWidgets, + activeSides: newActiveSides, + panelOrder: newActiveSides, + }; + + // Delete the selectedZone state + console.log('updatedZone: ', updatedZone); + setSelectedZone(updatedZone); + } else { + // If the panel is not active, activate it + const newActiveSides = [...selectedZone.activeSides, side]; + + const updatedZone = { + ...selectedZone, + activeSides: newActiveSides, + panelOrder: newActiveSides, + }; + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + let response = panelData(organization, selectedZone.zoneId, newActiveSides) + console.log('response: ', response); + + // Update the selectedZone state + console.log('updatedZone: ', updatedZone); + setSelectedZone(updatedZone); + } + }; + + return ( + <> + +
+ {(["top", "right", "bottom", "left"] as Side[]).map((side) => ( +
+ {/* "+" Button */} + + + {/* Extra Buttons */} + {selectedZone.activeSides.includes(side) && ( +
+ {/* Hide Panel */} +
toggleVisibility(side)} + > + +
+ + {/* Clean Panel */} +
cleanPanel(side)} + > + +
+ + {/* Lock/Unlock Panel */} +
toggleLockPanel(side)} + > + +
+
+ )} +
+ ))} +
+ + ); +}; + +export default AddButtons; diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index e699f27..56c67bb 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -11,6 +11,9 @@ interface DisplayZoneProps { panelOrder: Side[]; lockedPanels: Side[]; widgets: Widget[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; }; }; selectedZone: { @@ -18,6 +21,9 @@ interface DisplayZoneProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: { id: string; type: string; @@ -32,6 +38,9 @@ interface DisplayZoneProps { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: { id: string; type: string; @@ -152,16 +161,16 @@ const DisplayZone: React.FC = ({ return (
{Object.keys(zonesData).map((zoneName, index) => (
{ - console.log('zoneName: ', zoneName); + setSelectedZone({ zoneName, @@ -169,12 +178,15 @@ const DisplayZone: React.FC = ({ panelOrder: zonesData[zoneName].panelOrder || [], lockedPanels: zonesData[zoneName].lockedPanels || [], widgets: zonesData[zoneName].widgets || [], - }) + zoneId: zonesData[zoneName]?.zoneId || "", + zoneViewPortTarget: zonesData[zoneName].zoneViewPortTarget || [], + zoneViewPortPosition: + zonesData[zoneName].zoneViewPortPosition || [], + }); // setSelectedZone({ // zoneName, // ...zonesData[zoneName], // }); - console.log(selectedZone); }} > {zoneName} @@ -184,4 +196,4 @@ const DisplayZone: React.FC = ({ ); }; -export default DisplayZone; \ No newline at end of file +export default DisplayZone; diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx new file mode 100644 index 0000000..19b1717 --- /dev/null +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; + +const DroppedObjects = () => { + const { camera } = useThree(); // Now inside Canvas ✅ + const [objects, setObjects] = useState<{ id: number; position: [number, number, number] }[]>([]); + + // Function to convert drop event into 3D position + const handleDrop = (event: DragEvent) => { + event.preventDefault(); + + const data = event.dataTransfer?.getData("text/plain"); + if (!data) return; + + try { + const cardData = JSON.parse(data); + if (!cardData.className.includes("floating total-card")) { + console.log("Drop rejected: Incorrect element."); + return; + } + + // Convert 2D drop position to 3D world coordinates + const x = (event.clientX / window.innerWidth) * 2 - 1; + const y = -(event.clientY / window.innerHeight) * 2 + 1; + + // Raycasting to determine the drop position in 3D + const raycaster = new THREE.Raycaster(); + const mouseVector = new THREE.Vector2(x, y); + raycaster.setFromCamera(mouseVector, camera); + + // Intersect with a ground plane (assume y = 0) + const groundPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); + const intersection = new THREE.Vector3(); + raycaster.ray.intersectPlane(groundPlane, intersection); + + console.log("Spawn Object at:", intersection); + + // Add the dropped object to the scene state + setObjects((prev) => [...prev, { id: Date.now(), position: [intersection.x, intersection.y, intersection.z] }]); + } catch (error) { + console.error("Invalid data:", error); + } + }; + + return ( + + {/* Render dropped objects as green boxes */} + {objects.map((obj) => ( + + + + + ))} + + ); +}; + +export default DroppedObjects; diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index ed49d41..88a994c 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -1,245 +1,251 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { useWidgetStore } from "../../../store/useWidgetStore"; -import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; -import { DraggableWidget } from "./DraggableWidget"; -import { arrayMove } from "@dnd-kit/sortable"; - -type Side = "top" | "bottom" | "left" | "right"; - -interface Widget { - id: string; - type: string; - title: string; - panel: Side; - data: any; -} - -interface PanelProps { - selectedZone: { - zoneName: string; - activeSides: Side[]; - panelOrder: Side[]; - lockedPanels: Side[]; - widgets: Widget[]; - }; - setSelectedZone: React.Dispatch< - React.SetStateAction<{ - zoneName: string; - activeSides: Side[]; - panelOrder: Side[]; - lockedPanels: Side[]; - widgets: Widget[]; - }> - >; - hiddenPanels: string[]; -} - -const generateUniqueId = () => - `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - -const Panel: React.FC = ({ - selectedZone, - setSelectedZone, - hiddenPanels, -}) => { - const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({}); - const [panelDimensions, setPanelDimensions] = useState<{ - [side in Side]?: { width: number; height: number }; - }>({}); - - const { isPlaying } = usePlayButtonStore(); - - const getPanelStyle = useMemo( - () => (side: Side) => { - const currentIndex = selectedZone.panelOrder.indexOf(side); - const previousPanels = selectedZone.panelOrder.slice(0, currentIndex); - const leftActive = previousPanels.includes("left"); - const rightActive = previousPanels.includes("right"); - const topActive = previousPanels.includes("top"); - const bottomActive = previousPanels.includes("bottom"); - const panelSize = isPlaying ? 300 : 210; - - switch (side) { - case "top": - case "bottom": - return { - width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) - }px)`, - height: `${panelSize - 5}px`, - left: leftActive ? `${panelSize}px` : "0", - right: rightActive ? `${panelSize}px` : "0", - [side]: "0", - }; - case "left": - case "right": - return { - width: `${panelSize - 5}px`, - height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) - }px)`, - top: topActive ? `${panelSize}px` : "0", - bottom: bottomActive ? `${panelSize}px` : "0", - [side]: "0", - }; - default: - return {}; - } - }, - [selectedZone.panelOrder, isPlaying] - ); - - const handleDrop = (e: React.DragEvent, panel: Side) => { - e.preventDefault(); - const { draggedAsset } = useWidgetStore.getState(); - if (!draggedAsset) return; - if (isPanelLocked(panel)) return; - - const currentWidgetsCount = getCurrentWidgetCount(panel); - const maxCapacity = calculatePanelCapacity(panel); - - if (currentWidgetsCount >= maxCapacity) return; - - console.log('draggedAsset: ', draggedAsset); - console.log('panel: ', panel); - addWidgetToPanel(draggedAsset, panel); - }; - - const isPanelLocked = (panel: Side) => - selectedZone.lockedPanels.includes(panel); - - const getCurrentWidgetCount = (panel: Side) => - selectedZone.widgets.filter((w) => w.panel === panel).length; - - const calculatePanelCapacity = (panel: Side) => { - const CHART_WIDTH = 150; - const CHART_HEIGHT = 150; - const FALLBACK_HORIZONTAL_CAPACITY = 5; - const FALLBACK_VERTICAL_CAPACITY = 3; - - const dimensions = panelDimensions[panel]; - if (!dimensions) { - return panel === "top" || panel === "bottom" - ? FALLBACK_HORIZONTAL_CAPACITY - : FALLBACK_VERTICAL_CAPACITY; - } - - return panel === "top" || panel === "bottom" - ? Math.floor(dimensions.width / CHART_WIDTH) - : Math.floor(dimensions.height / CHART_HEIGHT); - }; - - const addWidgetToPanel = (asset: any, panel: Side) => { - const newWidget = { - ...asset, - id: generateUniqueId(), - panel, - }; - - setSelectedZone((prev) => ({ - ...prev, - widgets: [...prev.widgets, newWidget], - })); - }; - - useEffect(() => { - const observers: ResizeObserver[] = []; - const currentPanelRefs = panelRefs.current; - - selectedZone.activeSides.forEach((side) => { - const element = currentPanelRefs[side]; - if (element) { - const observer = new ResizeObserver((entries) => { - for (const entry of entries) { - const { width, height } = entry.contentRect; - setPanelDimensions((prev) => ({ - ...prev, - [side]: { width, height }, - })); - } - }); - observer.observe(element); - observers.push(observer); - } - }); - - return () => { - observers.forEach((observer) => observer.disconnect()); - }; - }, [selectedZone.activeSides]); - - const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => { - if (!selectedZone) return; // Ensure selectedZone is not null - console.log('selectedZone: ', selectedZone); - - setSelectedZone((prev) => { - if (!prev) return prev; // Ensure prev is not null - - // Filter widgets for the specified panel - const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel); - - // Reorder widgets within the same panel - const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex); - - // Merge the reordered widgets back into the full list while preserving the order - const updatedWidgets = prev.widgets - .filter((widget) => widget.panel !== panel) // Keep widgets from other panels - .concat(reorderedWidgets); // Add the reordered widgets for the specified panel - - return { - ...prev, - widgets: updatedWidgets, - }; - }); - }; - - - - - return ( - <> - {selectedZone.activeSides.map((side) => ( -
handleDrop(e, side)} - onDragOver={(e) => e.preventDefault()} - ref={(el) => { - if (el) { - panelRefs.current[side] = el; - } else { - delete panelRefs.current[side]; - } - }} - > -
- {selectedZone.widgets - .filter((w) => w.panel === side) - .map((widget, index) => ( - - handleReorder(fromIndex, toIndex, side) - } - /> - ))} -
-
- ))} - - ); -}; - -export default Panel; - - +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { useWidgetStore } from "../../../store/useWidgetStore"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import { DraggableWidget } from "./DraggableWidget"; +import { arrayMove } from "@dnd-kit/sortable"; + +type Side = "top" | "bottom" | "left" | "right"; + +interface Widget { + id: string; + type: string; + title: string; + panel: Side; + data: any; +} + +interface PanelProps { + selectedZone: { + zoneName: string; + activeSides: Side[]; + panelOrder: Side[]; + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] + widgets: Widget[]; + }; + setSelectedZone: React.Dispatch< + React.SetStateAction<{ + zoneName: string; + activeSides: Side[]; + panelOrder: Side[]; + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] + widgets: Widget[]; + }> + >; + hiddenPanels: string[]; +} + +const generateUniqueId = () => + `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + +const Panel: React.FC = ({ + selectedZone, + setSelectedZone, + hiddenPanels, +}) => { + const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({}); + const [panelDimensions, setPanelDimensions] = useState<{ + [side in Side]?: { width: number; height: number }; + }>({}); + + const { isPlaying } = usePlayButtonStore(); + + const getPanelStyle = useMemo( + () => (side: Side) => { + const currentIndex = selectedZone.panelOrder.indexOf(side); + const previousPanels = selectedZone.panelOrder.slice(0, currentIndex); + const leftActive = previousPanels.includes("left"); + const rightActive = previousPanels.includes("right"); + const topActive = previousPanels.includes("top"); + const bottomActive = previousPanels.includes("bottom"); + const panelSize = isPlaying ? 300 : 210; + + switch (side) { + case "top": + case "bottom": + return { + width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) + }px)`, + height: `${panelSize - 5}px`, + left: leftActive ? `${panelSize}px` : "0", + right: rightActive ? `${panelSize}px` : "0", + [side]: "0", + }; + case "left": + case "right": + return { + width: `${panelSize - 5}px`, + height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) + }px)`, + top: topActive ? `${panelSize}px` : "0", + bottom: bottomActive ? `${panelSize}px` : "0", + [side]: "0", + }; + default: + return {}; + } + }, + [selectedZone.panelOrder, isPlaying] + ); + + const handleDrop = (e: React.DragEvent, panel: Side) => { + e.preventDefault(); + const { draggedAsset } = useWidgetStore.getState(); + if (!draggedAsset) return; + if (isPanelLocked(panel)) return; + + const currentWidgetsCount = getCurrentWidgetCount(panel); + const maxCapacity = calculatePanelCapacity(panel); + + if (currentWidgetsCount >= maxCapacity) return; + + console.log('draggedAsset: ', draggedAsset); + console.log('panel: ', panel); + addWidgetToPanel(draggedAsset, panel); + }; + + const isPanelLocked = (panel: Side) => + selectedZone.lockedPanels.includes(panel); + + const getCurrentWidgetCount = (panel: Side) => + selectedZone.widgets.filter((w) => w.panel === panel).length; + + const calculatePanelCapacity = (panel: Side) => { + const CHART_WIDTH = 150; + const CHART_HEIGHT = 150; + const FALLBACK_HORIZONTAL_CAPACITY = 5; + const FALLBACK_VERTICAL_CAPACITY = 3; + + const dimensions = panelDimensions[panel]; + if (!dimensions) { + return panel === "top" || panel === "bottom" + ? FALLBACK_HORIZONTAL_CAPACITY + : FALLBACK_VERTICAL_CAPACITY; + } + + return panel === "top" || panel === "bottom" + ? Math.floor(dimensions.width / CHART_WIDTH) + : Math.floor(dimensions.height / CHART_HEIGHT); + }; + + const addWidgetToPanel = (asset: any, panel: Side) => { + const newWidget = { + ...asset, + id: generateUniqueId(), + panel, + }; + + setSelectedZone((prev) => ({ + ...prev, + widgets: [...prev.widgets, newWidget], + })); + }; + + useEffect(() => { + const observers: ResizeObserver[] = []; + const currentPanelRefs = panelRefs.current; + + selectedZone.activeSides.forEach((side) => { + const element = currentPanelRefs[side]; + if (element) { + const observer = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + setPanelDimensions((prev) => ({ + ...prev, + [side]: { width, height }, + })); + } + }); + observer.observe(element); + observers.push(observer); + } + }); + + return () => { + observers.forEach((observer) => observer.disconnect()); + }; + }, [selectedZone.activeSides]); + + const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => { + if (!selectedZone) return; // Ensure selectedZone is not null + console.log('selectedZone: ', selectedZone); + + setSelectedZone((prev) => { + if (!prev) return prev; // Ensure prev is not null + + // Filter widgets for the specified panel + const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel); + + // Reorder widgets within the same panel + const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex); + + // Merge the reordered widgets back into the full list while preserving the order + const updatedWidgets = prev.widgets + .filter((widget) => widget.panel !== panel) // Keep widgets from other panels + .concat(reorderedWidgets); // Add the reordered widgets for the specified panel + + return { + ...prev, + widgets: updatedWidgets, + }; + }); + }; + + + + + return ( + <> + {selectedZone.activeSides.map((side) => ( +
handleDrop(e, side)} + onDragOver={(e) => e.preventDefault()} + ref={(el) => { + if (el) { + panelRefs.current[side] = el; + } else { + delete panelRefs.current[side]; + } + }} + > +
+ {selectedZone.widgets + .filter((w) => w.panel === side) + .map((widget, index) => ( + + handleReorder(fromIndex, toIndex, side) + } + /> + ))} +
+
+ ))} + + ); +}; + +export default Panel; + + diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 0a8d1a3..f5efce3 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -1,147 +1,157 @@ -import React, { useEffect, useState, useRef } from "react"; -import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; -import Panel from "./Panel"; -import AddButtons from "./AddButtons"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; -import DisplayZone from "./DisplayZone"; -import Scene from "../../../modules/scene/scene"; -import useModuleStore from "../../../store/useModuleStore"; -import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; - - -type Side = "top" | "bottom" | "left" | "right"; - -type FormattedZoneData = Record< - string, - { - activeSides: Side[]; - panelOrder: Side[]; - lockedPanels: Side[]; - zoneCentrePoint: number[]; - widgets: Widget[]; - } ->; -type Widget = { - id: string; - type: string; - title: string; - panel: Side; - data: any; -}; -type Zone = { - zoneId: string; - zoneName: string; - points: number[][]; - layer: number; -}; - -const RealTimeVisulization: React.FC = () => { - const [hiddenPanels, setHiddenPanels] = React.useState([]); - const containerRef = useRef(null); - const { isPlaying } = usePlayButtonStore(); - const { activeModule } = useModuleStore(); - - const [zonesData, setZonesData] = useState({}); - const { selectedZone, setSelectedZone } = useSelectedZoneStore(); - - useEffect(() => { - async function GetZoneData() { - try { - const response: { data: Zone[] } | undefined = await getZonesApi( - "hexrfactory" - ); - - if (!response || !response.data) { - return; - } - const formattedData = response?.data?.reduce( - (acc, zone) => { - acc[zone.zoneName] = { - activeSides: [], - panelOrder: [], - lockedPanels: [], - zoneCentrePoint: [], - widgets: [], - }; - return acc; - }, - {} - ); - setZonesData(formattedData); - } catch (error) { } - } - GetZoneData(); - }, []); - - useEffect(() => { - - console.log('zonesData: ', zonesData); - }, [zonesData]); - - useEffect(() => { - setZonesData((prev) => { - if (!selectedZone) return prev; - - return { - ...prev, - [selectedZone.zoneName]: { - ...prev[selectedZone.zoneName], // Keep existing properties - activeSides: selectedZone.activeSides || [], - panelOrder: selectedZone.panelOrder || [], - lockedPanels: selectedZone.lockedPanels || [], - widgets: selectedZone.widgets || [], - }, - }; - }); - }, [selectedZone]); - - return ( -
-
- -
- {activeModule === "visualization" && ( - <> - - - {!isPlaying && ( - - )} - - - - )} -
- ); -}; - -export default RealTimeVisulization; +import React, { useEffect, useState, useRef } from "react"; +import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import Panel from "./Panel"; +import AddButtons from "./AddButtons"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import DisplayZone from "./DisplayZone"; +import Scene from "../../../modules/scene/scene"; +import useModuleStore from "../../../store/useModuleStore"; +import { useZones } from "../../../store/store"; + + + +type Side = "top" | "bottom" | "left" | "right"; + +type FormattedZoneData = Record< + string, + { + activeSides: Side[]; + panelOrder: Side[]; + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[] + widgets: Widget[]; + } +>; +type Widget = { + id: string; + type: string; + title: string; + panel: Side; + data: any; +}; + +const RealTimeVisulization: React.FC = () => { + const [hiddenPanels, setHiddenPanels] = React.useState([]); + const containerRef = useRef(null); + const { isPlaying } = usePlayButtonStore(); + const { activeModule } = useModuleStore(); + + const [zonesData, setZonesData] = useState({}); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const { zones } = useZones() + + useEffect(() => { + const data = Array.isArray(zones) ? zones : []; + console.log('data: ', data); + const formattedData = data.reduce((acc, zone) => { + acc[zone.zoneName] = { + activeSides: [], + panelOrder: [], + lockedPanels: [], + zoneId: zone.zoneId, + zoneViewPortTarget: zone.viewPortCenter, + zoneViewPortPosition: zone.viewPortposition, + widgets: [], + }; + return acc; + }, {}); + + setZonesData(formattedData); + }, [zones]); + + useEffect(() => { + setZonesData((prev) => { + if (!selectedZone) return prev; + return { + ...prev, + [selectedZone.zoneName]: { + ...prev[selectedZone.zoneName], // Keep existing properties + activeSides: selectedZone.activeSides || [], + panelOrder: selectedZone.panelOrder || [], + lockedPanels: selectedZone.lockedPanels || [], + zoneId: selectedZone.zoneId || "", + zoneViewPortTarget: selectedZone.zoneViewPortTarget || [], + zoneViewPortPosition: selectedZone.zoneViewPortPosition || [], + widgets: selectedZone.widgets || [], + }, + }; + }); + }, [selectedZone]); + + const handleDrop = (event: React.DragEvent) => { + event.preventDefault(); + const canvas = document.querySelector(".scene-container"); + if (canvas) { + // Extract relevant properties manually + const dragEvent = new DragEvent("drop", { + bubbles: true, + cancelable: true, + dataTransfer: event.dataTransfer, // Attach dataTransfer manually ✅ + }); + + console.log('dragEvent: ', dragEvent); + canvas.dispatchEvent(dragEvent); + } + }; + + + return ( +
+
+ {/* {objects.map((obj) => ( + + + + + ))} */} + +
+ {activeModule === "visualization" && ( + <> + + + {!isPlaying && selectedZone?.zoneName !== "" && ( + + )} + + + + )} +
+ ); +}; + +export default RealTimeVisulization; diff --git a/app/src/components/ui/componets/zoneCameraTarget.tsx b/app/src/components/ui/componets/zoneCameraTarget.tsx new file mode 100644 index 0000000..8605afa --- /dev/null +++ b/app/src/components/ui/componets/zoneCameraTarget.tsx @@ -0,0 +1,96 @@ +import { useEffect, useMemo, useRef, useState } from "react"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; + +export default function ZoneCentreTarget() { + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const [previousZoneCentre, setPreviousZoneCentre] = useState(null); + const sphereRef = useRef(null); + const { camera, controls }: any = useThree(); + + + useEffect(() => { + if ( + selectedZone.zoneViewPortTarget && + JSON.stringify(previousZoneCentre) !== JSON.stringify(selectedZone.zoneViewPortTarget) + ) { + setPreviousZoneCentre(selectedZone.zoneViewPortTarget); + } + }, [selectedZone.zoneViewPortTarget, previousZoneCentre]); + + const centrePoint = useMemo(() => { + if (!previousZoneCentre || !selectedZone.zoneViewPortTarget) return null; + return previousZoneCentre.map((value, index) => + (value + selectedZone.zoneViewPortTarget[index]) / 2 + ); + }, [previousZoneCentre, selectedZone.zoneViewPortTarget]); + + useEffect(() => { + if (selectedZone.zoneName !== "") { + if (sphereRef.current) { + sphereRef.current.position.set(selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2]); + } + if (centrePoint) { + + if (centrePoint.length > 0) { + + let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition); + let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget); + + const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize(); + + const worldUp = new THREE.Vector3(0, 0, 1); + const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize(); + const up = new THREE.Vector3().crossVectors(direction, right).normalize(); + + const offsetPosition = up.clone().multiplyScalar(20); + + camPosition.add(offsetPosition); + + + const setCam = async () => { + controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true); + setTimeout(() => { + controls?.setLookAt( + ...camPosition.toArray(), + selectedZone.zoneViewPortTarget[0], + selectedZone.zoneViewPortTarget[1], + selectedZone.zoneViewPortTarget[2], + true + ); + }, 400) + }; + setCam(); + } else { + + let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition); + let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget); + + const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize(); + + const worldUp = new THREE.Vector3(0, 0, 1); + const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize(); + const up = new THREE.Vector3().crossVectors(direction, right).normalize(); + + const offsetPosition = up.clone().multiplyScalar(20); + + camPosition.add(offsetPosition); + const setCam = async () => { + controls?.setLookAt( + ...camPosition.toArray(), + selectedZone.zoneViewPortTarget[0], + selectedZone.zoneViewPortTarget[1], + selectedZone.zoneViewPortTarget[2], + true + ); + }; + setCam(); + } + } + } + }, [selectedZone.zoneViewPortTarget, camera, controls]); + return ( + <> + ); +} diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index a61054b..96985a3 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -2,7 +2,8 @@ import React, { useEffect, useState } from "react"; import List from "./List"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; -import { getZonesApi } from "../../../services/realTimeVisulization/zoneData/getZones"; +import { useZones } from "../../../store/store"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; interface DropDownListProps { value?: string; // Value to display in the DropDownList @@ -29,24 +30,23 @@ const DropDownList: React.FC = ({ defaultOpen = false, listType = "default", }) => { + const [isOpen, setIsOpen] = useState(defaultOpen); + const { zones, setZones } = useZones() const handleToggle = () => { setIsOpen((prev) => !prev); // Toggle the state }; const [zoneDataList, setZoneDataList] = useState<{ id: string; name: string }[]>([]); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); useEffect(() => { - async function GetZoneData() { - const response = await getZonesApi("hexrfactory") - console.log('response: ', response.data); - setZoneDataList([{ id: "1", name: "zone1" }, - { id: "2", name: "Zone 2" },]) - } - - GetZoneData() - - }, []) + const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({ + id: val.zoneId, + name: val.zoneName + })); + setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev)); + }, [zones]); return (
diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index bdf4749..75ff903 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -1,6 +1,9 @@ import React from "react"; import RenameInput from "../inputs/RenameInput"; import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones"; +import { useSubModuleStore } from "../../../store/useModuleStore"; interface ListProps { items?: { id: string; name: string }[]; // Optional array of items to render @@ -8,7 +11,28 @@ interface ListProps { } const List: React.FC = ({ items = [] }) => { - console.log('items: ', items); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const { subModule, setSubModule } = useSubModuleStore(); + + async function handleSelectZone(id: string) { + setSubModule("zoneProperties") + const email = localStorage.getItem('email') + const organization = (email!.split("@")[1]).split(".")[0]; + let response = await getZoneData(id, organization) + console.log('response: ', response); + setSelectedZone({ + zoneName: response?.zoneName, + activeSides: response?.activeSides || [], + panelOrder: response?.panelOrder || [], + lockedPanels: response?.lockedPanels || [], + widgets: response?.widgets || [], + zoneId: response?.zoneId, + zoneViewPortTarget: response?.viewPortCenter || [], + zoneViewPortPosition: + response?.viewPortposition || [], + }); + + } return ( <> {items.length > 0 ? ( @@ -16,7 +40,7 @@ const List: React.FC = ({ items = [] }) => { {items.map((item, index) => (
  • -
    +
    handleSelectZone(item.id)}>
    diff --git a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx index d67e87f..fca0c3d 100644 --- a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx +++ b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx @@ -13,8 +13,19 @@ const SimpleCard: React.FC = ({ value, per, }) => { + + const handleDragStart = (event: React.DragEvent) => { + const cardData = JSON.stringify({ + header, + value, + per, + className: event.currentTarget.className, // Store the class name + }); + event.dataTransfer.setData("text/plain", cardData); + }; + return ( -
    +
    {header}
    diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index f083395..38d0721 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -112,7 +112,7 @@ export default async function assetManager( ) { if (!activePromises.get(taskId)) return; // Stop processing if task is canceled - const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid); + const existingModel = itemsGroup?.current?.getObjectByProperty("uuid", item.modeluuid); if (existingModel) { // console.log(`Model ${item.modelname} already exists in the scene.`); resolve(); diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 8a370e9..3d47a7e 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -1,509 +1,511 @@ -import React, { useState, useEffect, useMemo, useRef } from "react"; -import { Line, Sphere } from "@react-three/drei"; -import { useThree, useFrame } from "@react-three/fiber"; -import * as THREE from "three"; -import { useActiveLayer, useDeleteModels, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store"; -// import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi"; -// import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi"; -import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; - -import * as CONSTANTS from '../../../types/world/worldConstants'; - -const ZoneGroup: React.FC = () => { - const { camera, pointer, gl, raycaster, scene, controls } = useThree(); - const [startPoint, setStartPoint] = useState(null); - const [endPoint, setEndPoint] = useState(null); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - const [isDragging, setIsDragging] = useState(false); - const [draggedSphere, setDraggedSphere] = useState(null); - const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const { toggleView } = useToggleView(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { removedLayer, setRemovedLayer } = useRemovedLayer(); - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); - const { deleteModels, setDeleteModels } = useDeleteModels(); - const { activeLayer, setActiveLayer } = useActiveLayer(); - const { socket } = useSocketStore(); - - const groupsRef = useRef(); - - const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({ - side: THREE.DoubleSide, - vertexShader: ` - varying vec2 vUv; - void main(){ - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - vUv = uv; - } - `, - fragmentShader: ` - varying vec2 vUv; - uniform vec3 uColor; - void main(){ - float alpha = 1.0 - vUv.y; - gl_FragColor = vec4(uColor, alpha); - } - `, - uniforms: { - uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, - }, - transparent: true, - }), []); - - useEffect(() => { - const fetchZones = async () => { - const email = localStorage.getItem('email'); - if (!email) return; - - const organization = email.split("@")[1].split(".")[0]; - const data = await getZonesApi(organization); - - if (data.data && data.data.length > 0) { - const fetchedZones = data.data.map((zone: any) => ({ - zoneId: zone.zoneId, - zoneName: zone.zoneName, - points: zone.points, - layer: zone.layer - })); - - setZones(fetchedZones); - - const fetchedPoints = data.data.flatMap((zone: any) => - zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) - ); - - setZonePoints(fetchedPoints); - } - }; - - fetchZones(); - }, []); - - useEffect(() => { - - localStorage.setItem('zones', JSON.stringify(zones)); - - }, [zones]) - - useEffect(() => { - if (removedLayer) { - const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); - setZones(updatedZones); - - const updatedzonePoints = zonePoints.filter((_: any, index: any) => { - const zoneIndex = Math.floor(index / 4); - return zones[zoneIndex]?.layer !== removedLayer; - }); - setZonePoints(updatedzonePoints); - - zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { - deleteZoneFromBackend(zone.zoneId); - }); - - setRemovedLayer(null); - } - }, [removedLayer]); - - useEffect(() => { - if (toolMode !== "Zone") { - setStartPoint(null); - setEndPoint(null); - } else { - setDeletePointOrLine(false); - setMovePoint(false); - setDeleteModels(false); - } - if (!toggleView) { - setStartPoint(null); - setEndPoint(null); - } - }, [toolMode, toggleView]); - - - const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { - - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target) return; - const position = [target[0], 75, target[2]]; - - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer - } - } - - socket.emit('v2:zone:set', input); - }; - - const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { - - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target) return; - const position = [target[0], 75, target[2]]; - - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer - } - } - - socket.emit('v2:zone:set', input); - }; - - - const deleteZoneFromBackend = async (zoneId: string) => { - - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const input = { - userId: userId, - organization: organization, - zoneId: zoneId - } - - socket.emit('v2:zone:delete', input); - }; - - const handleDeleteZone = (zoneId: string) => { - const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); - setZones(updatedZones); - - const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); - if (zoneIndex !== -1) { - const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); - zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); - const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); - setZonePoints(updatedzonePoints); - } - - deleteZoneFromBackend(zoneId); - }; - - useEffect(() => { - if (!camera || !toggleView) return; - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0 && movePoint) { - const clickedObject = intersects[0].object; - const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); - if (sphereIndex !== -1) { - (controls as any).enabled = false; - setDraggedSphere(zonePoints[sphereIndex]); - setIsDragging(true); - } - } - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { - isLeftMouseDown = false; - - if (!startPoint && !movePoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setStartPoint(point); - setEndPoint(null); - } - } else if (startPoint && !movePoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (!point) return; - - const points = [ - [startPoint.x, 0.15, startPoint.z], - [point.x, 0.15, startPoint.z], - [point.x, 0.15, point.z], - [startPoint.x, 0.15, point.z], - [startPoint.x, 0.15, startPoint.z], - ] as [number, number, number][]; - - const zoneName = `Zone ${zones.length + 1}`; - const zoneId = THREE.MathUtils.generateUUID(); - const newZone = { - zoneId, - zoneName, - points: points, - layer: activeLayer - }; - - const newZones = [...zones, newZone]; - - setZones(newZones); - - const newzonePoints = [ - new THREE.Vector3(startPoint.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, point.z), - new THREE.Vector3(startPoint.x, 0.15, point.z), - ]; - - const updatedZonePoints = [...zonePoints, ...newzonePoints]; - setZonePoints(updatedZonePoints); - - addZoneToBackend(newZone); - - setStartPoint(null); - setEndPoint(null); - } - } else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0) { - const clickedObject = intersects[0].object; - - const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const zoneId = zones[zoneIndex].zoneId; - handleDeleteZone(zoneId); - return; - } - } - } - - if (evt.button === 0) { - if (isDragging && draggedSphere) { - setIsDragging(false); - setDraggedSphere(null); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - - if (zoneIndex !== -1 && zones[zoneIndex]) { - updateZoneToBackend(zones[zoneIndex]); - } - } - } - } - }; - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0 && intersects[0].object.name.includes('point')) { - gl.domElement.style.cursor = movePoint ? "pointer" : "default"; - } else { - gl.domElement.style.cursor = "default"; - } - if (isDragging && draggedSphere) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - draggedSphere.set(point.x, 0.15, point.z); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const cornerIndex = sphereIndex % 4; - - const updatedZones = zones.map((zone: any, index: number) => { - if (index === zoneIndex) { - const updatedPoints = [...zone.points]; - updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; - updatedPoints[4] = updatedPoints[0]; - return { ...zone, points: updatedPoints }; - } - return zone; - }); - - setZones(updatedZones); - } - } - } - }; - - const onContext = (event: any) => { - event.preventDefault(); - setStartPoint(null); - setEndPoint(null); - }; - - if (toolMode === 'Zone' || deletePointOrLine || movePoint) { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("contextmenu", onContext); - } - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("contextmenu", onContext); - }; - }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]); - - useFrame(() => { - if (!startPoint) return; - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setEndPoint(point); - } - }); - return ( - - - {zones - .map((zone: any) => ( - - {zone.points.slice(0, -1).map((point: [number, number, number], index: number) => { - const nextPoint = zone.points[index + 1]; - - const point1 = new THREE.Vector3(point[0], point[1], point[2]); - const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]); - - const planeWidth = point1.distanceTo(point2); - const planeHeight = CONSTANTS.wallConfig.height; - - const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2); - - const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); - - return ( - - - - - ); - })} - - ))} - - - {zones - .filter((zone: any) => zone.layer === activeLayer) - .map((zone: any) => ( - { - e.stopPropagation(); - if (deletePointOrLine) { - handleDeleteZone(zone.zoneId); - } - }} - /> - ))} - - - {zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => ( - zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( - - - - )) - ))} - - - {startPoint && endPoint && ( - - )} - - - ); -}; - +import React, { useState, useEffect, useMemo, useRef } from "react"; +import { Line, Sphere } from "@react-three/drei"; +import { useThree, useFrame } from "@react-three/fiber"; +import * as THREE from "three"; +import { useActiveLayer, useDeleteModels, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store"; +// import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi"; +// import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi"; +import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; + +import * as CONSTANTS from '../../../types/world/worldConstants'; + +const ZoneGroup: React.FC = () => { + const { camera, pointer, gl, raycaster, scene, controls } = useThree(); + const [startPoint, setStartPoint] = useState(null); + const [endPoint, setEndPoint] = useState(null); + const { zones, setZones } = useZones(); + const { zonePoints, setZonePoints } = useZonePoints(); + const [isDragging, setIsDragging] = useState(false); + const [draggedSphere, setDraggedSphere] = useState(null); + const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); + const { toggleView } = useToggleView(); + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { removedLayer, setRemovedLayer } = useRemovedLayer(); + const { toolMode, setToolMode } = useToolMode(); + const { movePoint, setMovePoint } = useMovePoint(); + const { deleteModels, setDeleteModels } = useDeleteModels(); + const { activeLayer, setActiveLayer } = useActiveLayer(); + const { socket } = useSocketStore(); + + const groupsRef = useRef(); + + const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({ + side: THREE.DoubleSide, + vertexShader: ` + varying vec2 vUv; + void main(){ + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + vUv = uv; + } + `, + fragmentShader: ` + varying vec2 vUv; + uniform vec3 uColor; + void main(){ + float alpha = 1.0 - vUv.y; + gl_FragColor = vec4(uColor, alpha); + } + `, + uniforms: { + uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, + }, + transparent: true, + }), []); + + useEffect(() => { + const fetchZones = async () => { + const email = localStorage.getItem('email'); + if (!email) return; + + const organization = email.split("@")[1].split(".")[0]; + const data = await getZonesApi(organization); + + if (data.data && data.data.length > 0) { + const fetchedZones = data.data.map((zone: any) => ({ + zoneId: zone.zoneId, + zoneName: zone.zoneName, + points: zone.points, + viewPortCenter: zone.viewPortCenter, + viewPortposition: zone.viewPortposition, + layer: zone.layer + })); + + setZones(fetchedZones); + + const fetchedPoints = data.data.flatMap((zone: any) => + zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) + ); + + setZonePoints(fetchedPoints); + } + }; + + fetchZones(); + }, []); + + useEffect(() => { + + localStorage.setItem('zones', JSON.stringify(zones)); + + }, [zones]) + + useEffect(() => { + if (removedLayer) { + const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); + setZones(updatedZones); + + const updatedzonePoints = zonePoints.filter((_: any, index: any) => { + const zoneIndex = Math.floor(index / 4); + return zones[zoneIndex]?.layer !== removedLayer; + }); + setZonePoints(updatedzonePoints); + + zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { + deleteZoneFromBackend(zone.zoneId); + }); + + setRemovedLayer(null); + } + }, [removedLayer]); + + useEffect(() => { + if (toolMode !== "Zone") { + setStartPoint(null); + setEndPoint(null); + } else { + setDeletePointOrLine(false); + setMovePoint(false); + setDeleteModels(false); + } + if (!toggleView) { + setStartPoint(null); + setEndPoint(null); + } + }, [toolMode, toggleView]); + + + const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { + + const email = localStorage.getItem('email'); + const userId = localStorage.getItem('userId'); + const organization = (email!.split("@")[1]).split(".")[0]; + + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, sumY = 0, sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; + }; + + const target: [number, number, number] | null = calculateCenter(zone.points); + if (!target) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer + } + } + + socket.emit('v2:zone:set', input); + }; + + const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { + + const email = localStorage.getItem('email'); + const userId = localStorage.getItem('userId'); + const organization = (email!.split("@")[1]).split(".")[0]; + + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, sumY = 0, sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; + }; + + const target: [number, number, number] | null = calculateCenter(zone.points); + if (!target) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer + } + } + + socket.emit('v2:zone:set', input); + }; + + + const deleteZoneFromBackend = async (zoneId: string) => { + + const email = localStorage.getItem('email'); + const userId = localStorage.getItem('userId'); + const organization = (email!.split("@")[1]).split(".")[0]; + + const input = { + userId: userId, + organization: organization, + zoneId: zoneId + } + + socket.emit('v2:zone:delete', input); + }; + + const handleDeleteZone = (zoneId: string) => { + const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); + setZones(updatedZones); + + const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); + if (zoneIndex !== -1) { + const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); + zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); + const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); + setZonePoints(updatedzonePoints); + } + + deleteZoneFromBackend(zoneId); + }; + + useEffect(() => { + if (!camera || !toggleView) return; + const canvasElement = gl.domElement; + + let drag = false; + let isLeftMouseDown = false; + + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = true; + drag = false; + + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(groupsRef.current.children, true); + + if (intersects.length > 0 && movePoint) { + const clickedObject = intersects[0].object; + const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); + if (sphereIndex !== -1) { + (controls as any).enabled = false; + setDraggedSphere(zonePoints[sphereIndex]); + setIsDragging(true); + } + } + } + }; + + const onMouseUp = (evt: any) => { + if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { + isLeftMouseDown = false; + + if (!startPoint && !movePoint) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + setStartPoint(point); + setEndPoint(null); + } + } else if (startPoint && !movePoint) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (!point) return; + + const points = [ + [startPoint.x, 0.15, startPoint.z], + [point.x, 0.15, startPoint.z], + [point.x, 0.15, point.z], + [startPoint.x, 0.15, point.z], + [startPoint.x, 0.15, startPoint.z], + ] as [number, number, number][]; + + const zoneName = `Zone ${zones.length + 1}`; + const zoneId = THREE.MathUtils.generateUUID(); + const newZone = { + zoneId, + zoneName, + points: points, + layer: activeLayer + }; + + const newZones = [...zones, newZone]; + + setZones(newZones); + + const newzonePoints = [ + new THREE.Vector3(startPoint.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, point.z), + new THREE.Vector3(startPoint.x, 0.15, point.z), + ]; + + const updatedZonePoints = [...zonePoints, ...newzonePoints]; + setZonePoints(updatedZonePoints); + + addZoneToBackend(newZone); + + setStartPoint(null); + setEndPoint(null); + } + } else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(groupsRef.current.children, true); + + if (intersects.length > 0) { + const clickedObject = intersects[0].object; + + const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const zoneId = zones[zoneIndex].zoneId; + handleDeleteZone(zoneId); + return; + } + } + } + + if (evt.button === 0) { + if (isDragging && draggedSphere) { + setIsDragging(false); + setDraggedSphere(null); + + const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + + if (zoneIndex !== -1 && zones[zoneIndex]) { + updateZoneToBackend(zones[zoneIndex]); + } + } + } + } + }; + + const onMouseMove = () => { + if (isLeftMouseDown) { + drag = true; + } + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects(groupsRef.current.children, true); + + if (intersects.length > 0 && intersects[0].object.name.includes('point')) { + gl.domElement.style.cursor = movePoint ? "pointer" : "default"; + } else { + gl.domElement.style.cursor = "default"; + } + if (isDragging && draggedSphere) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + draggedSphere.set(point.x, 0.15, point.z); + + const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const cornerIndex = sphereIndex % 4; + + const updatedZones = zones.map((zone: any, index: number) => { + if (index === zoneIndex) { + const updatedPoints = [...zone.points]; + updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; + updatedPoints[4] = updatedPoints[0]; + return { ...zone, points: updatedPoints }; + } + return zone; + }); + + setZones(updatedZones); + } + } + } + }; + + const onContext = (event: any) => { + event.preventDefault(); + setStartPoint(null); + setEndPoint(null); + }; + + if (toolMode === 'Zone' || deletePointOrLine || movePoint) { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("contextmenu", onContext); + } + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]); + + useFrame(() => { + if (!startPoint) return; + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + setEndPoint(point); + } + }); + return ( + + + {zones + .map((zone: any) => ( + + {zone.points.slice(0, -1).map((point: [number, number, number], index: number) => { + const nextPoint = zone.points[index + 1]; + + const point1 = new THREE.Vector3(point[0], point[1], point[2]); + const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]); + + const planeWidth = point1.distanceTo(point2); + const planeHeight = CONSTANTS.wallConfig.height; + + const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.wallConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.wallConfig.height), (point1.z + point2.z) / 2); + + const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); + + return ( + + + + + ); + })} + + ))} + + + {zones + .filter((zone: any) => zone.layer === activeLayer) + .map((zone: any) => ( + { + e.stopPropagation(); + if (deletePointOrLine) { + handleDeleteZone(zone.zoneId); + } + }} + /> + ))} + + + {zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => ( + zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( + + + + )) + ))} + + + {startPoint && endPoint && ( + + )} + + + ); +}; + export default ZoneGroup; \ No newline at end of file diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index e9ca9e0..031629f 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -745,6 +745,7 @@ export default function SocketResponses({ return } if (data.message === "zone deleted") { + console.log('data: ', data); const updatedZones = zones.filter((zone: any) => zone.zoneId !== data.data.zoneId); setZones(updatedZones); diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 3aaff94..9286a66 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import { Canvas } from "@react-three/fiber"; import { Environment, KeyboardControls } from "@react-three/drei"; @@ -15,6 +15,11 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr"; import SelectionControls from "./controls/selection/selectionControls"; import MeasurementTool from "./tools/measurementTool"; import Simulation from "../simulation/simulation"; +import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget"; + +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets"; // import Simulation from "./simulationtemp/simulation"; export default function Scene() { @@ -27,6 +32,9 @@ export default function Scene() { // { name: "jump", keys: ["Space"] }, ], []) + + + return ( { e.preventDefault(); }} + > + + {/* */} diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index 5675a6a..39031d8 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,25 +1,23 @@ -let url_Backend_dwinzo = `http://185.100.212.76:5000`; - -export const getZonesApi = async (organization: string) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v2/findZones/${organization}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); - - // if (!response.ok) { - // throw new Error("Failed to get Zones"); - // } - - 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"); - } - } -}; \ No newline at end of file +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +export const getZoneData = async (zoneId: string, organization: string) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to fetch zoneData"); + } + + return await response.json(); + } catch (error: any) { + throw new Error(error.message); + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/panel.tsx b/app/src/services/realTimeVisulization/zoneData/panel.tsx new file mode 100644 index 0000000..793bedb --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/panel.tsx @@ -0,0 +1,31 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + +type Side = "top" | "bottom" | "left" | "right"; + +export const panelData = async (organization: string, zoneID: string, panelOrder: Side[]) => { + console.log('panelOrder: ', panelOrder); + console.log('zoneID: ', zoneID); + console.log('organization: ', organization); + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v1/panel/save`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneID, panelOrder }), + }); + + if (!response.ok) { + throw new Error("Failed to add panelOrder for 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"); + } + } +}; \ No newline at end of file diff --git a/app/src/store/useZoneStore.ts b/app/src/store/useZoneStore.ts index e0a66f0..007a1c6 100644 --- a/app/src/store/useZoneStore.ts +++ b/app/src/store/useZoneStore.ts @@ -15,21 +15,31 @@ interface SelectedZoneState { activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; widgets: Widget[]; } interface SelectedZoneStore { selectedZone: SelectedZoneState; - setSelectedZone: (zone: Partial | ((prev: SelectedZoneState) => SelectedZoneState)) => void; + setSelectedZone: ( + zone: + | Partial + | ((prev: SelectedZoneState) => SelectedZoneState) + ) => void; } export const useSelectedZoneStore = create((set) => ({ selectedZone: { - zoneName: "", - activeSides: [], - panelOrder: [], - lockedPanels: [], - widgets: [], + zoneName: "", // Empty string initially + activeSides: [], // Empty array + panelOrder: [], // Empty array + lockedPanels: [], // Empty array + zoneId: "", + zoneViewPortTarget: [], + zoneViewPortPosition: [], + widgets: [], // Empty array }, setSelectedZone: (zone) => set((state) => ({ @@ -38,4 +48,4 @@ export const useSelectedZoneStore = create((set) => ({ ? zone(state.selectedZone) // Handle functional updates : { ...state.selectedZone, ...zone }, // Handle partial updates })), -})); \ No newline at end of file +}));