Merge branch 'realTimeVisulization' of http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev into realTimeVisulization

This commit is contained in:
gabriel 2025-03-26 18:46:00 +05:30
commit 558236c458
18 changed files with 1465 additions and 1162 deletions

View File

@ -49,25 +49,22 @@ const SideBarRight: React.FC = () => {
{activeModule === "simulation" && (
<>
<div
className={`sidebar-action-list ${
subModule === "mechanics" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")}
>
<MechanicsIcon isActive={activeList === "mechanics"} />
</div>
<div
className={`sidebar-action-list ${
subModule === "simulations" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")}
>
<SimulationIcon isActive={activeList === "simulations"} />
</div>
<div
className={`sidebar-action-list ${
subModule === "analysis" ? "active" : ""
}`}
className={`sidebar-action-list ${subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")}
>
<AnalysisIcon isActive={activeList === "analysis"} />
@ -78,7 +75,18 @@ const SideBarRight: React.FC = () => {
)}
{/* process builder */}
{toggleUI &&
activeList === "properties" &&
subModule === "zoneProperties" &&
activeModule === "builder" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
{/* <GlobalProperties /> */}
<ZoneProperties />
{/* <AsstePropertiies /> */}
</div>
</div>
)}
{toggleUI &&
subModule === "properties" &&
activeModule !== "visualization" && (
<div className="sidebar-right-container">
<div className="sidebar-right-content-container">
@ -88,7 +96,6 @@ const SideBarRight: React.FC = () => {
</div>
</div>
)}
{/* simulation */}
{toggleUI && activeModule === "simulation" && (

View File

@ -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 (
<div className="zone-properties-container">
<div className="header">
<RenameInput value="Selected Zone Name" />
<RenameInput value={selectedZone.zoneName ? selectedZone.zoneName : ""} />
<div className="button" onClick={handleEditView}>
{Edit ? "Cancel" : "Edit"}
</div>
</div>
<Vector3Input onChange={() => {}} header="Viewport Target" />
<Vector3Input onChange={() => {}} header="Viewport Position" />
<Vector3Input onChange={() => { }} header="Viewport Target" />
<Vector3Input onChange={() => { }} header="Viewport Position" />
{Edit && (
<div className="button-save" onClick={handleSetView}>
Set View

View File

@ -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<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
}
const AddButtons: React.FC<ButtonsProps> = ({
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 (
<div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}>
<button
className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)}
title={
selectedZone.activeSides.includes(side)
? `Remove all items and close ${side} panel`
: `Activate ${side} panel`
}
>
+
</button>
{/* Extra Buttons */}
{selectedZone.activeSides.includes(side) && (
<div className="extra-Bs">
{/* Hide Panel */}
<div
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
}`}
title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
}
onClick={() => toggleVisibility(side)}
>
<EyeIcon
fill={hiddenPanels.includes(side) ? "white" : "#1D1E21"}
/>
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Lock/Unlock Panel */}
<div
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon fill={selectedZone.lockedPanels.includes(side) ? "#ffffff" : "#1D1E21"} />
</div>
</div>
)}
</div>
))}
</div>
);
};
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<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
}
const AddButtons: React.FC<ButtonsProps> = ({
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 (
<>
<div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */}
<button
className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)}
title={
selectedZone.activeSides.includes(side)
? `Remove all items and close ${side} panel`
: `Activate ${side} panel`
}
>
+
</button>
{/* Extra Buttons */}
{selectedZone.activeSides.includes(side) && (
<div className="extra-Bs">
{/* Hide Panel */}
<div
className={`icon ${hiddenPanels.includes(side) ? "active" : ""
}`}
title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
}
onClick={() => toggleVisibility(side)}
>
<EyeIcon
fill={
hiddenPanels.includes(side)
? "white"
: "#1D1E21"
}
/>
</div>
{/* Clean Panel */}
<div
className="icon"
title="Clean Panel"
onClick={() => cleanPanel(side)}
>
<CleanPannel />
</div>
{/* Lock/Unlock Panel */}
<div
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={
selectedZone.lockedPanels.includes(side)
? "Unlock Panel"
: "Lock Panel"
}
onClick={() => toggleLockPanel(side)}
>
<LockIcon fill={selectedZone.lockedPanels.includes(side) ? "#ffffff" : "#1D1E21"} />
</div>
</div>
)}
</div>
))}
</div>
</>
);
};
export default AddButtons;

View File

@ -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<DisplayZoneProps> = ({
return (
<div
ref={containerRef}
className={`zoon-wrapper ${selectedZone.activeSides.includes("bottom") && "bottom"
className={`zoon-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
}`}
>
{Object.keys(zonesData).map((zoneName, index) => (
<div
key={index}
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
}`}
}`}
onClick={() => {
console.log('zoneName: ', zoneName);
setSelectedZone({
zoneName,
@ -169,12 +178,15 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
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<DisplayZoneProps> = ({
);
};
export default DisplayZone;
export default DisplayZone;

View File

@ -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 (
<group>
{/* Render dropped objects as green boxes */}
{objects.map((obj) => (
<mesh key={obj.id} position={obj.position}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="green" />
</mesh>
))}
</group>
);
};
export default DroppedObjects;

View File

@ -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<PanelProps> = ({
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) => (
<div
key={side}
className={`panel ${side}-panel absolute ${isPlaying && ""}`}
style={getPanelStyle(side)}
onDrop={(e) => handleDrop(e, side)}
onDragOver={(e) => e.preventDefault()}
ref={(el) => {
if (el) {
panelRefs.current[side] = el;
} else {
delete panelRefs.current[side];
}
}}
>
<div
className={`panel-content ${isPlaying && "fullScreen"}`}
style={{
pointerEvents: selectedZone.lockedPanels.includes(side)
? "none"
: "auto",
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
}}
>
{selectedZone.widgets
.filter((w) => w.panel === side)
.map((widget, index) => (
<DraggableWidget
hiddenPanels={hiddenPanels}
widget={widget}
key={widget.id}
index={index}
onReorder={(fromIndex, toIndex) =>
handleReorder(fromIndex, toIndex, side)
}
/>
))}
</div>
</div>
))}
</>
);
};
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<PanelProps> = ({
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) => (
<div
key={side}
className={`panel ${side}-panel absolute ${isPlaying && ""}`}
style={getPanelStyle(side)}
onDrop={(e) => handleDrop(e, side)}
onDragOver={(e) => e.preventDefault()}
ref={(el) => {
if (el) {
panelRefs.current[side] = el;
} else {
delete panelRefs.current[side];
}
}}
>
<div
className={`panel-content ${isPlaying && "fullScreen"}`}
style={{
pointerEvents: selectedZone.lockedPanels.includes(side)
? "none"
: "auto",
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
}}
>
{selectedZone.widgets
.filter((w) => w.panel === side)
.map((widget, index) => (
<DraggableWidget
hiddenPanels={hiddenPanels}
widget={widget}
key={widget.id}
index={index}
onReorder={(fromIndex, toIndex) =>
handleReorder(fromIndex, toIndex, side)
}
/>
))}
</div>
</div>
))}
</>
);
};
export default Panel;

View File

@ -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<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null);
const { isPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore();
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
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<FormattedZoneData>(
(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 (
<div
ref={containerRef}
id="real-time-vis-canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
<div
className="scene-container"
style={{
height: "100%",
width: "100%",
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
>
<Scene />
</div>
{activeModule === "visualization" && (
<>
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
{!isPlaying && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)}
<Panel
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
hiddenPanels={hiddenPanels}
/>
</>
)}
</div>
);
};
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<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null);
const { isPlaying } = usePlayButtonStore();
const { activeModule } = useModuleStore();
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zones } = useZones()
useEffect(() => {
const data = Array.isArray(zones) ? zones : [];
console.log('data: ', data);
const formattedData = data.reduce<FormattedZoneData>((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<HTMLDivElement>) => {
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 (
<div
ref={containerRef}
id="real-time-vis-canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
<div
className="scene-container"
style={{
height: "100%",
width: "100%",
borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
}}
onDrop={handleDrop}
>
{/* {objects.map((obj) => (
<mesh key={obj.id} position={obj.position}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="green" />
</mesh>
))} */}
<Scene />
</div>
{activeModule === "visualization" && (
<>
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
{!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)}
<Panel
hiddenPanels={hiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
</>
)}
</div>
);
};
export default RealTimeVisulization;

View File

@ -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<number[] | null>(null);
const sphereRef = useRef<THREE.Mesh>(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 (
<> </>
);
}

View File

@ -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<DropDownListProps> = ({
defaultOpen = false,
listType = "default",
}) => {
const [isOpen, setIsOpen] = useState<boolean>(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 (
<div className="dropdown-list-container">

View File

@ -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<ListProps> = ({ 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<ListProps> = ({ items = [] }) => {
{items.map((item, index) => (
<li key={index} className="list-container">
<div className="list-item">
<div className="value">
<div className="value" onClick={() => handleSelectZone(item.id)}>
<RenameInput value={item.name} />
</div>
<div className="options-container">

View File

@ -13,8 +13,19 @@ const SimpleCard: React.FC<SimpleCardProps> = ({
value,
per,
}) => {
const handleDragStart = (event: React.DragEvent<HTMLDivElement>) => {
const cardData = JSON.stringify({
header,
value,
per,
className: event.currentTarget.className, // Store the class name
});
event.dataTransfer.setData("text/plain", cardData);
};
return (
<div className="floating total-card" draggable>
<div className="floating total-card" draggable onDragStart={handleDragStart}>
<div className="header-wrapper">
<div className="header">{header}</div>
<div className="data-values">

View File

@ -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();

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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 (
<KeyboardControls map={map}>
<Canvas
@ -36,12 +44,15 @@ export default function Scene() {
onContextMenu={(e) => {
e.preventDefault();
}}
>
<DroppedObjects/>
<Controls />
<TransformControl />
<SelectionControls />
<MeasurementTool />
<World />
<ZoneCentreTarget />
{/* <Simulation /> */}
<Simulation />
<PostProcessing />

View File

@ -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");
}
}
};
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);
}
};

View File

@ -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");
}
}
};

View File

@ -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<SelectedZoneState> | ((prev: SelectedZoneState) => SelectedZoneState)) => void;
setSelectedZone: (
zone:
| Partial<SelectedZoneState>
| ((prev: SelectedZoneState) => SelectedZoneState)
) => void;
}
export const useSelectedZoneStore = create<SelectedZoneStore>((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<SelectedZoneStore>((set) => ({
? zone(state.selectedZone) // Handle functional updates
: { ...state.selectedZone, ...zone }, // Handle partial updates
})),
}));
}));