3d widget api added and template frontend and backend completed
This commit is contained in:
@@ -1,25 +1,76 @@
|
||||
import { useEffect } from "react";
|
||||
import { useDroppedObjectsStore } from "../../../../store/useDroppedObjectsStore";
|
||||
import useTemplateStore from "../../../../store/useTemplateStore";
|
||||
import { useSelectedZoneStore } from "../../../../store/useZoneStore";
|
||||
import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate";
|
||||
import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate";
|
||||
import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate";
|
||||
|
||||
const Templates = () => {
|
||||
const { templates, removeTemplate } = useTemplateStore();
|
||||
const { setSelectedZone } = useSelectedZoneStore();
|
||||
const { setTemplates } = useTemplateStore();
|
||||
const { setSelectedZone, selectedZone } = useSelectedZoneStore();
|
||||
|
||||
const handleDeleteTemplate = (id: string) => {
|
||||
removeTemplate(id);
|
||||
useEffect(() => {
|
||||
async function templateData() {
|
||||
try {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let response = await getTemplateData(organization);
|
||||
setTemplates(response);
|
||||
} catch (error) {
|
||||
console.error("Error fetching template data:", error);
|
||||
}
|
||||
}
|
||||
|
||||
templateData();
|
||||
}, []);
|
||||
|
||||
const handleDeleteTemplate = async (id: string) => {
|
||||
try {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
let response = await deleteTemplateApi(id, organization);
|
||||
|
||||
if (response.message === "Template deleted successfully") {
|
||||
removeTemplate(id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting template:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoadTemplate = (template: any) => {
|
||||
setSelectedZone((prev) => ({
|
||||
...prev,
|
||||
panelOrder: template.panelOrder,
|
||||
activeSides: Array.from(
|
||||
new Set([...prev.activeSides, ...template.panelOrder])
|
||||
),
|
||||
widgets: template.widgets,
|
||||
}));
|
||||
const handleLoadTemplate = async (template: any) => {
|
||||
try {
|
||||
if (selectedZone.zoneName === "") return;
|
||||
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization);
|
||||
|
||||
if (response.message === "Template placed in Zone") {
|
||||
setSelectedZone({
|
||||
panelOrder: template.panelOrder,
|
||||
activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides`
|
||||
widgets: template.widgets,
|
||||
});
|
||||
|
||||
useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||
|
||||
if (Array.isArray(template.floatingWidget)) {
|
||||
template.floatingWidget.forEach((val: any) => {
|
||||
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading template:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
className="template-list"
|
||||
@@ -41,7 +92,7 @@ const Templates = () => {
|
||||
transition: "box-shadow 0.3s ease",
|
||||
}}
|
||||
>
|
||||
{template.snapshot && (
|
||||
{template?.snapshot && (
|
||||
<div style={{ position: "relative", paddingBottom: "56.25%" }}>
|
||||
{" "}
|
||||
{/* 16:9 aspect ratio */}
|
||||
@@ -122,3 +173,4 @@ const Templates = () => {
|
||||
};
|
||||
|
||||
export default Templates;
|
||||
|
||||
|
||||
@@ -20,17 +20,16 @@ const ZoneProperties: React.FC = () => {
|
||||
try {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
|
||||
let zonesdata = {
|
||||
zoneId: selectedZone.zoneId,
|
||||
viewPortposition: zonePosition,
|
||||
viewPortCenter: zoneTarget
|
||||
};
|
||||
|
||||
|
||||
let response = await zoneCameraUpdate(zonesdata, organization);
|
||||
console.log('response: ', response);
|
||||
|
||||
|
||||
|
||||
setEdit(false);
|
||||
} catch (error) {
|
||||
console.error("Error in handleSetView:", error);
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
useTransformMode,
|
||||
} from "../../store/store";
|
||||
import useToggleStore from "../../store/useUIToggleStore";
|
||||
import { use3DWidget, useFloatingWidget } from "../../store/useDroppedObjectsStore";
|
||||
|
||||
const Tools: React.FC = () => {
|
||||
const { templates } = useTemplateStore();
|
||||
@@ -46,6 +47,8 @@ const Tools: React.FC = () => {
|
||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||
const { addTemplate } = useTemplateStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { floatingWidget } = useFloatingWidget()
|
||||
const { widgets3D } = use3DWidget()
|
||||
|
||||
// wall options
|
||||
const { toggleView, setToggleView } = useToggleView();
|
||||
@@ -378,13 +381,17 @@ const Tools: React.FC = () => {
|
||||
<div className="draw-tools">
|
||||
<div
|
||||
className={`tool-button`}
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
|
||||
handleSaveTemplate({
|
||||
addTemplate,
|
||||
floatingWidget,
|
||||
widgets3D,
|
||||
selectedZone,
|
||||
templates,
|
||||
})
|
||||
}
|
||||
}
|
||||
>
|
||||
<SaveTemplateIcon isActive={false} />
|
||||
</div>
|
||||
|
||||
@@ -119,7 +119,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||
};
|
||||
|
||||
// Delete the selectedZone state
|
||||
|
||||
setSelectedZone(updatedZone);
|
||||
} else {
|
||||
const updatePanelData = async () => {
|
||||
|
||||
@@ -2,9 +2,10 @@ import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||
import { Widget } from "../../../store/useWidgetStore";
|
||||
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
|
||||
import { InfoIcon } from "../../icons/ExportCommonIcons";
|
||||
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
|
||||
import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore";
|
||||
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
|
||||
import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData";
|
||||
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
||||
|
||||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
@@ -72,6 +73,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
// State to track overflow visibility
|
||||
const [showLeftArrow, setShowLeftArrow] = useState(false);
|
||||
const [showRightArrow, setShowRightArrow] = useState(false);
|
||||
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
|
||||
|
||||
// Function to calculate overflow state
|
||||
const updateOverflowState = useCallback(() => {
|
||||
@@ -150,14 +152,16 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
async function handleSelect2dZoneData(zoneId: string, zoneName: string) {
|
||||
try {
|
||||
if (selectedZone?.zoneId === zoneId) {
|
||||
console.log("Zone is already selected:", zoneName);
|
||||
|
||||
return;
|
||||
}
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
// Fetch data from backend
|
||||
let response = await getSelect2dZoneData(zoneId, organization);
|
||||
console.log('response: ', response);
|
||||
let res = await getFloatingZoneData(zoneId, organization);
|
||||
setFloatingWidget(res)
|
||||
// Set the selected zone in the store
|
||||
useDroppedObjectsStore.getState().setZone(zoneName, zoneId);
|
||||
if (Array.isArray(res)) {
|
||||
@@ -177,8 +181,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
zoneViewPortPosition: response.viewPortposition || {},
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('error: ', error);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,9 +190,8 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`zone-wrapper ${
|
||||
selectedZone?.activeSides?.includes("bottom") && "bottom"
|
||||
}`}
|
||||
className={`zone-wrapper ${selectedZone?.activeSides?.includes("bottom") && "bottom"
|
||||
}`}
|
||||
>
|
||||
{/* Left Arrow */}
|
||||
{showLeftArrow && (
|
||||
|
||||
93
app/src/components/ui/componets/DistanceLine.tsx
Normal file
93
app/src/components/ui/componets/DistanceLine.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React from "react";
|
||||
|
||||
interface DistanceLinesProps {
|
||||
obj: {
|
||||
position: {
|
||||
top?: number | "auto";
|
||||
left?: number | "auto";
|
||||
right?: number | "auto";
|
||||
bottom?: number | "auto";
|
||||
};
|
||||
};
|
||||
activeEdges: {
|
||||
vertical: "top" | "bottom";
|
||||
horizontal: "left" | "right";
|
||||
} | null;
|
||||
}
|
||||
|
||||
const DistanceLines: React.FC<DistanceLinesProps> = ({ obj, activeEdges }) => {
|
||||
if (!activeEdges) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{activeEdges.vertical === "top" && typeof obj.position.top === "number" && (
|
||||
<div
|
||||
className="distance-line top"
|
||||
style={{
|
||||
top: 0,
|
||||
left:
|
||||
activeEdges.horizontal === "left"
|
||||
? `${(obj.position.left as number) + 125}px`
|
||||
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
|
||||
height: `${obj.position.top}px`,
|
||||
}}
|
||||
>
|
||||
<span className="distance-label">{obj.position.top.toFixed()}px</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeEdges.vertical === "bottom" &&
|
||||
typeof obj.position.bottom === "number" && (
|
||||
<div
|
||||
className="distance-line bottom"
|
||||
style={{
|
||||
bottom: 0,
|
||||
left:
|
||||
activeEdges.horizontal === "left"
|
||||
? `${(obj.position.left as number) + 125}px`
|
||||
: `calc(100% - ${(obj.position.right as number) + 125}px)`,
|
||||
height: `${obj.position.bottom}px`,
|
||||
}}
|
||||
>
|
||||
<span className="distance-label">{obj.position.bottom.toFixed()}px</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeEdges.horizontal === "left" &&
|
||||
typeof obj.position.left === "number" && (
|
||||
<div
|
||||
className="distance-line left"
|
||||
style={{
|
||||
left: 0,
|
||||
top:
|
||||
activeEdges.vertical === "top"
|
||||
? `${(obj.position.top as number) + 41.5}px`
|
||||
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
|
||||
width: `${obj.position.left}px`,
|
||||
}}
|
||||
>
|
||||
<span className="distance-label">{obj.position.left.toFixed()}px</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeEdges.horizontal === "right" &&
|
||||
typeof obj.position.right === "number" && (
|
||||
<div
|
||||
className="distance-line right"
|
||||
style={{
|
||||
right: 0,
|
||||
top:
|
||||
activeEdges.vertical === "top"
|
||||
? `${(obj.position.top as number) + 41.5}px`
|
||||
: `calc(100% - ${(obj.position.bottom as number) + 41.5}px)`,
|
||||
width: `${obj.position.right}px`,
|
||||
}}
|
||||
>
|
||||
<span className="distance-label">{obj.position.right.toFixed()}px</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DistanceLines;
|
||||
@@ -10,79 +10,139 @@ import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity";
|
||||
import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment";
|
||||
import StateWorking from "../../layout/3D-cards/cards/StateWorking";
|
||||
import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
||||
import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget";
|
||||
import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData";
|
||||
import { use3DWidget } from "../../../store/useDroppedObjectsStore";
|
||||
|
||||
export default function Dropped3dWidgets() {
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
const { widgetSelect } = useAsset3dWidget();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { raycaster, gl, scene }: ThreeState = useThree();
|
||||
const { selectedZone } = useSelectedZoneStore(); // Get currently selected zone
|
||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption()
|
||||
// 🔥 Store widget positions per zone
|
||||
const [zoneWidgets, setZoneWidgets] = useState<Record<
|
||||
string, // Zone ID
|
||||
Record<string, [number, number, number][]> // Widget type -> Positions array
|
||||
>>({});
|
||||
|
||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||
const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone
|
||||
// 🔥 Store widget data (id, type, position) based on the selected zone
|
||||
const [zoneWidgetData, setZoneWidgetData] = useState<
|
||||
Record<string, { id: string; type: string; position: [number, number, number] }[]>
|
||||
>({});
|
||||
const { setWidgets3D } = use3DWidget()
|
||||
|
||||
useEffect(() => {
|
||||
if (widgetSubOption === "Floating") return
|
||||
// if (activeModule !== "visualization") return;
|
||||
const canvasElement = gl.domElement;
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault(); // Prevent default browser behavior
|
||||
if (widgetSubOption === "3D") {
|
||||
if (selectedZone.zoneName === "") return
|
||||
if (!widgetSelect?.startsWith("ui")) return;
|
||||
const group1 = scene.getObjectByName("itemsGroup");
|
||||
if (!group1) return;
|
||||
const Assets = group1.children
|
||||
.map((val) => scene.getObjectByProperty("uuid", val.uuid))
|
||||
.filter(Boolean) as THREE.Object3D[];
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(
|
||||
(intersect) =>
|
||||
!intersect.object.name.includes("Roof") &&
|
||||
!intersect.object.name.includes("agv-collider") &&
|
||||
!intersect.object.name.includes("MeasurementReference") &&
|
||||
!intersect.object.userData.isPathObject &&
|
||||
!(intersect.object.type === "GridHelper")
|
||||
);
|
||||
if (intersects.length > 0) {
|
||||
const { x, y, z } = intersects[0].point;
|
||||
if (activeModule !== "visualization") return
|
||||
if (selectedZone.zoneName === "") return;
|
||||
|
||||
setZoneWidgets((prev) => ({
|
||||
...prev,
|
||||
[selectedZone.zoneId]: {
|
||||
...(prev[selectedZone.zoneId] || {}),
|
||||
[widgetSelect]: [...(prev[selectedZone.zoneId]?.[widgetSelect] || []), [x, y, z]],
|
||||
},
|
||||
}));
|
||||
}
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
async function get3dWidgetData() {
|
||||
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
|
||||
setWidgets3D(result)
|
||||
// Ensure the extracted data has id, type, and position correctly mapped
|
||||
const formattedWidgets = result.map((widget: any) => ({
|
||||
id: widget.id,
|
||||
type: widget.type,
|
||||
position: widget.position,
|
||||
}));
|
||||
|
||||
setZoneWidgetData((prev) => ({
|
||||
...prev,
|
||||
[selectedZone.zoneId]: formattedWidgets,
|
||||
}));
|
||||
}
|
||||
|
||||
get3dWidgetData();
|
||||
|
||||
}, [selectedZone.zoneId,activeModule]);
|
||||
// useEffect(() => {
|
||||
// // ✅ Set data only for the selected zone, keeping existing state structure
|
||||
// setZoneWidgetData((prev) => ({
|
||||
// ...prev,
|
||||
// [selectedZone.zoneId]: [
|
||||
// {
|
||||
// "id": "1743322674626-50mucpb1c",
|
||||
// "type": "ui-Widget 1",
|
||||
// "position": [120.94655021768133, 4.142360029666558, 124.39283546121099]
|
||||
// },
|
||||
// {
|
||||
// "id": "1743322682086-je2h9x33v",
|
||||
// "type": "ui-Widget 2",
|
||||
// "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362]
|
||||
// }
|
||||
// ]
|
||||
// }));
|
||||
// }, [selectedZone.zoneId]); // ✅ Only update when the zone changes
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== "visualization") return;
|
||||
if (widgetSubOption === "Floating") return;
|
||||
if (selectedZone.zoneName === "") return
|
||||
const canvasElement = gl.domElement;
|
||||
const onDrop = async (event: DragEvent) => {
|
||||
event.preventDefault(); // Prevent default browser behavior
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
if (!widgetSelect.startsWith("ui")) return;
|
||||
const group1 = scene.getObjectByName("itemsGroup");
|
||||
if (!group1) return;
|
||||
const intersects = raycaster.intersectObjects(scene.children, true).filter(
|
||||
(intersect) =>
|
||||
!intersect.object.name.includes("Roof") &&
|
||||
!intersect.object.name.includes("agv-collider") &&
|
||||
!intersect.object.name.includes("MeasurementReference") &&
|
||||
!intersect.object.userData.isPathObject &&
|
||||
!(intersect.object.type === "GridHelper")
|
||||
);
|
||||
if (intersects.length > 0) {
|
||||
const { x, y, z } = intersects[0].point;
|
||||
|
||||
// ✅ Explicitly define position as a tuple
|
||||
const newWidget: { id: string; type: string; position: [number, number, number] } = {
|
||||
id: generateUniqueId(),
|
||||
type: widgetSelect,
|
||||
position: [x, y, z], // Ensures TypeScript recognizes it as a tuple
|
||||
};
|
||||
|
||||
|
||||
let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget)
|
||||
|
||||
|
||||
// ✅ Store widgets uniquely for each zone
|
||||
setZoneWidgetData((prev) => ({
|
||||
...prev,
|
||||
[selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget],
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
canvasElement.addEventListener("drop", onDrop);
|
||||
return () => {
|
||||
canvasElement.removeEventListener("drop", onDrop)
|
||||
// setWidgetSelect()
|
||||
canvasElement.removeEventListener("drop", onDrop);
|
||||
};
|
||||
}, [widgetSelect, activeModule, widgetSubOption]);
|
||||
}, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]);
|
||||
|
||||
// Get widgets for the currently active zone
|
||||
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
|
||||
|
||||
return (
|
||||
<>
|
||||
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 1"]?.map((pos, index) => (
|
||||
<ProductionCapacity key={`Widget1-${index}`} position={pos} />
|
||||
))}
|
||||
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 2"]?.map((pos, index) => (
|
||||
<ReturnOfInvestment key={`Widget2-${index}`} position={pos} />
|
||||
))}
|
||||
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 3"]?.map((pos, index) => (
|
||||
<StateWorking key={`Widget3-${index}`} position={pos} />
|
||||
))}
|
||||
{zoneWidgets[selectedZone.zoneId]?.["ui-Widget 4"]?.map((pos, index) => (
|
||||
<Throughput key={`Widget4-${index}`} position={pos} />
|
||||
))}
|
||||
{activeZoneWidgets.map(({ id, type, position }) => {
|
||||
switch (type) {
|
||||
case "ui-Widget 1":
|
||||
return <ProductionCapacity key={id} position={position} />;
|
||||
case "ui-Widget 2":
|
||||
return <ReturnOfInvestment key={id} position={position} />;
|
||||
case "ui-Widget 3":
|
||||
return <StateWorking key={id} position={position} />;
|
||||
case "ui-Widget 4":
|
||||
return <Throughput key={id} position={position} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import { WalletIcon } from "../../icons/3dChartIcons";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
@@ -14,6 +15,7 @@ import {
|
||||
DeleteIcon,
|
||||
} from "../../icons/ExportCommonIcons";
|
||||
import DistanceLines from "./DistanceLines"; // Import the DistanceLines component
|
||||
import { deleteFloatingWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteFloatingWidget";
|
||||
|
||||
interface DraggingState {
|
||||
zone: string;
|
||||
@@ -26,12 +28,25 @@ interface DraggingState {
|
||||
};
|
||||
}
|
||||
|
||||
interface DraggingState {
|
||||
zone: string;
|
||||
index: number;
|
||||
initialPosition: {
|
||||
top: number | "auto";
|
||||
left: number | "auto";
|
||||
right: number | "auto";
|
||||
bottom: number | "auto";
|
||||
};
|
||||
}
|
||||
const DroppedObjects: React.FC = () => {
|
||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
||||
const updateObjectPosition = useDroppedObjectsStore(
|
||||
(state) => state.updateObjectPosition
|
||||
);
|
||||
const deleteObject = useDroppedObjectsStore((state) => state.deleteObject);
|
||||
|
||||
const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject);
|
||||
const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
|
||||
null
|
||||
);
|
||||
@@ -62,6 +77,28 @@ const DroppedObjects: React.FC = () => {
|
||||
if (zoneEntries.length === 0) return null;
|
||||
const [zoneName, zone] = zoneEntries[0];
|
||||
|
||||
function handleDuplicate(zoneName: string, index: number) {
|
||||
setOpenKebabId(null)
|
||||
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
||||
}
|
||||
|
||||
async function handleDelete(zoneName: string, id: string, index: number) {
|
||||
try {
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
|
||||
let res = await deleteFloatingWidgetApi(id, organization);
|
||||
console.log('res: ', res);
|
||||
|
||||
if (res.message === "FloatingWidget deleted successfully") {
|
||||
deleteObject(zoneName, index); // Call the deleteObject method from the store
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting floating widget:", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||
const obj = zone.objects[index];
|
||||
const container = document.getElementById("real-time-vis-canvas");
|
||||
@@ -228,11 +265,12 @@ const DroppedObjects: React.FC = () => {
|
||||
animationRef.current = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in handlePointerUp:", error);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const handleKebabClick = (id: string, event: React.MouseEvent) => {
|
||||
|
||||
event.stopPropagation();
|
||||
setOpenKebabId((prevId) => (prevId === id ? null : id));
|
||||
};
|
||||
@@ -337,13 +375,19 @@ const DroppedObjects: React.FC = () => {
|
||||
</div>
|
||||
{openKebabId === obj.id && (
|
||||
<div className="kebab-options">
|
||||
<div className="dublicate btn">
|
||||
<div className="dublicate btn" onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDuplicate(zoneName, index); // Call the duplicate handler
|
||||
}}>
|
||||
<div className="icon">
|
||||
<DublicateIcon />
|
||||
</div>
|
||||
<div className="label">Duplicate</div>
|
||||
</div>
|
||||
<div className="edit btn">
|
||||
<div className="edit btn" onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleDelete(zoneName, obj.id, index); // Call the delete handler
|
||||
}}>
|
||||
<div className="icon">
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
@@ -388,4 +432,4 @@ const DroppedObjects: React.FC = () => {
|
||||
|
||||
export default DroppedObjects;
|
||||
|
||||
// in pointer move even when i goes to top right the value not changes to top right same problem in bottom left
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
try {
|
||||
const response = await getZone2dData(organization);
|
||||
|
||||
if (!Array.isArray(response)) {
|
||||
return;
|
||||
}
|
||||
@@ -83,7 +84,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
);
|
||||
setZonesData(formattedData);
|
||||
} catch (error) {
|
||||
console.log("error: ", error);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
});
|
||||
}, [selectedZone]);
|
||||
|
||||
useEffect(() => {}, [floatingWidgets]);
|
||||
// useEffect(() => {}, [floatingWidgets]);
|
||||
|
||||
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
||||
try {
|
||||
@@ -135,6 +136,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
id: generateUniqueId(),
|
||||
position: determinePosition(canvasRect, relativeX, relativeY),
|
||||
};
|
||||
console.log('newObject: ', newObject);
|
||||
|
||||
let response = await addingFloatingWidgets(
|
||||
selectedZone.zoneId,
|
||||
@@ -150,7 +152,6 @@ const RealTimeVisulization: React.FC = () => {
|
||||
.getState()
|
||||
.setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||
}
|
||||
|
||||
// Add the dropped object to the zone if the API call is successful
|
||||
if (response.message === "FloatWidget created successfully") {
|
||||
useDroppedObjectsStore
|
||||
@@ -171,7 +172,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
],
|
||||
},
|
||||
}));
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -198,7 +199,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||
>
|
||||
<Scene />
|
||||
</div>
|
||||
<DroppedObjects />
|
||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
|
||||
{activeModule === "visualization" && (
|
||||
<>
|
||||
<DisplayZone
|
||||
|
||||
@@ -1,3 +1,70 @@
|
||||
// export function determinePosition(
|
||||
// canvasRect: DOMRect,
|
||||
// relativeX: number,
|
||||
// relativeY: number
|
||||
// ): {
|
||||
// top: number | "auto";
|
||||
// left: number | "auto";
|
||||
// right: number | "auto";
|
||||
// bottom: number | "auto";
|
||||
// } {
|
||||
// // Calculate the midpoints of the canvas
|
||||
// const centerX = canvasRect.width / 2;
|
||||
// const centerY = canvasRect.height / 2;
|
||||
|
||||
// // Initialize position with default values
|
||||
// let position: {
|
||||
// top: number | "auto";
|
||||
// left: number | "auto";
|
||||
// right: number | "auto";
|
||||
// bottom: number | "auto";
|
||||
// };
|
||||
|
||||
// if (relativeY < centerY) {
|
||||
// // Top half
|
||||
// if (relativeX < centerX) {
|
||||
// // Left side
|
||||
// position = {
|
||||
// top: relativeY,
|
||||
// left: relativeX,
|
||||
// right: "auto",
|
||||
// bottom: "auto",
|
||||
// };
|
||||
// } else {
|
||||
// // Right side
|
||||
// position = {
|
||||
// top: relativeY,
|
||||
// right: canvasRect.width - relativeX,
|
||||
// left: "auto",
|
||||
// bottom: "auto",
|
||||
// };
|
||||
// }
|
||||
// } else {
|
||||
// // Bottom half
|
||||
// if (relativeX < centerX) {
|
||||
// // Left side
|
||||
// position = {
|
||||
// bottom: canvasRect.height - relativeY,
|
||||
// left: relativeX,
|
||||
// right: "auto",
|
||||
// top: "auto",
|
||||
// };
|
||||
// } else {
|
||||
// // Right side
|
||||
// position = {
|
||||
// bottom: canvasRect.height - relativeY,
|
||||
// right: canvasRect.width - relativeX,
|
||||
// left: "auto",
|
||||
// top: "auto",
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
// return position;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
export function determinePosition(
|
||||
canvasRect: DOMRect,
|
||||
relativeX: number,
|
||||
|
||||
29
app/src/components/ui/componets/handleDropTemplate .tsx
Normal file
29
app/src/components/ui/componets/handleDropTemplate .tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
// import { useSelectedZoneStore } from "../../../store/useZoneStore";
|
||||
|
||||
|
||||
// type HandleDropTemplateProps = {
|
||||
// templateId: string;
|
||||
// };
|
||||
|
||||
// export const handleDropTemplate = ({ templateId }: HandleDropTemplateProps): void => {
|
||||
// const { getTemplate } = useTemplateStore.getState();
|
||||
// const { setSelectedZone } = useSelectedZoneStore.getState();
|
||||
|
||||
// // Find the template by ID
|
||||
// const template: Template | undefined = getTemplate(templateId);
|
||||
|
||||
// if (!template) {
|
||||
// console.error("Template not found!");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Update the selected zone with the template data
|
||||
// setSelectedZone((prev) => ({
|
||||
// ...prev,
|
||||
// panelOrder: template.panelOrder,
|
||||
// activeSides: Array.from(new Set([...prev.activeSides, ...template.panelOrder])),
|
||||
// widgets: template.widgets, // Keep widget structure the same
|
||||
// }));
|
||||
|
||||
// console.log("Dropped template applied:", template);
|
||||
// };
|
||||
Reference in New Issue
Block a user