Files
Dwinzo_dev/app/src/components/ui/componets/DroppedFloatingWidgets.tsx

392 lines
12 KiB
TypeScript
Raw Normal View History

2025-03-27 18:04:16 +05:30
import { WalletIcon } from "../../icons/3dChartIcons";
import { useEffect, useRef, useState } from "react";
import {
useDroppedObjectsStore,
Zones,
} from "../../../store/useDroppedObjectsStore";
import useModuleStore from "../../../store/useModuleStore";
import { determinePosition } from "./functions/determinePosition";
import { getActiveProperties } from "./functions/getActiveProperties";
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
2025-03-31 18:22:40 +05:30
import {
DublicateIcon,
KebabIcon,
DeleteIcon,
} from "../../icons/ExportCommonIcons";
import DistanceLines from "./DistanceLines"; // Import the DistanceLines component
interface DraggingState {
zone: string;
index: number;
initialPosition: {
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
};
}
2025-03-27 12:28:17 +05:30
2025-03-27 18:04:16 +05:30
const DroppedObjects: React.FC = () => {
const zones = useDroppedObjectsStore((state) => state.zones);
2025-03-31 18:22:40 +05:30
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
const updateObjectPosition = useDroppedObjectsStore(
(state) => state.updateObjectPosition
);
2025-03-31 18:22:40 +05:30
const [draggingIndex, setDraggingIndex] = useState<DraggingState | null>(
null
);
2025-03-27 18:04:16 +05:30
const [offset, setOffset] = useState<[number, number] | null>(null);
2025-03-31 18:22:40 +05:30
const [activeEdges, setActiveEdges] = useState<{
vertical: "top" | "bottom";
horizontal: "left" | "right";
} | null>(null); // State to track active edges for distance lines
const [currentPosition, setCurrentPosition] = useState<{
top: number | "auto";
left: number | "auto";
right: number | "auto";
bottom: number | "auto";
} | null>(null); // State to track the current position during drag
2025-03-27 18:04:16 +05:30
const animationRef = useRef<number | null>(null);
const { activeModule } = useModuleStore();
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
// Clean up animation frame on unmount
useEffect(() => {
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
};
}, []);
2025-03-27 18:04:16 +05:30
const zoneEntries = Object.entries(zones);
2025-03-31 18:22:40 +05:30
if (zoneEntries.length === 0) return null;
const [zoneName, zone] = zoneEntries[0];
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
const handlePointerDown = (event: React.PointerEvent, index: number) => {
2025-03-27 18:04:16 +05:30
const obj = zone.objects[index];
const container = document.getElementById("real-time-vis-canvas");
if (!container) return;
const rect = container.getBoundingClientRect();
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
2025-03-31 18:22:40 +05:30
// Determine active properties for the initial position
const [activeProp1, activeProp2] = getActiveProperties(obj.position);
2025-03-31 18:22:40 +05:30
// Set active edges for distance lines
const vertical = activeProp1 === "top" ? "top" : "bottom";
const horizontal = activeProp2 === "left" ? "left" : "right";
setActiveEdges({ vertical, horizontal });
// Store the initial position strategy and active edges
setDraggingIndex({
zone: zoneName,
index,
initialPosition: { ...obj.position },
});
// Calculate offset from mouse to object edges
let offsetX = 0;
let offsetY = 0;
if (activeProp1 === "top") {
2025-03-31 18:22:40 +05:30
offsetY = relativeY - (obj.position.top as number);
} else {
offsetY = rect.height - relativeY - (obj.position.bottom as number);
}
if (activeProp2 === "left") {
2025-03-31 18:22:40 +05:30
offsetX = relativeX - (obj.position.left as number);
} else {
offsetX = rect.width - relativeX - (obj.position.right as number);
}
2025-03-27 18:04:16 +05:30
setOffset([offsetY, offsetX]);
2025-03-31 18:22:40 +05:30
};
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
const handlePointerMove = (event: React.PointerEvent) => {
2025-03-27 18:04:16 +05:30
if (!draggingIndex || !offset) return;
const container = document.getElementById("real-time-vis-canvas");
if (!container) return;
const rect = container.getBoundingClientRect();
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
2025-03-31 18:22:40 +05:30
// Dynamically determine the current position strategy
const newPositionStrategy = determinePosition(rect, relativeX, relativeY);
const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy);
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
// Update active edges for distance lines
const vertical = activeProp1 === "top" ? "top" : "bottom";
const horizontal = activeProp2 === "left" ? "left" : "right";
setActiveEdges({ vertical, horizontal });
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
// Calculate new position based on the active properties
let newY = 0;
let newX = 0;
if (activeProp1 === "top") {
newY = relativeY - offset[0];
2025-03-31 18:22:40 +05:30
} else {
newY = rect.height - (relativeY + offset[0]);
}
2025-03-31 18:22:40 +05:30
if (activeProp2 === "left") {
newX = relativeX - offset[1];
} else {
newX = rect.width - (relativeX + offset[1]);
}
// Apply boundaries
2025-03-27 18:04:16 +05:30
newX = Math.max(0, Math.min(rect.width - 50, newX));
newY = Math.max(0, Math.min(rect.height - 50, newY));
2025-03-31 18:22:40 +05:30
// Create new position object
const newPosition = {
...newPositionStrategy,
[activeProp1]: newY,
[activeProp2]: newX,
// Clear opposite properties
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
[activeProp2 === "left" ? "right" : "left"]: "auto",
};
// Update the current position state for DistanceLines
setCurrentPosition(newPosition);
2025-03-27 18:04:16 +05:30
if (!animationRef.current) {
animationRef.current = requestAnimationFrame(() => {
2025-03-31 18:22:40 +05:30
updateObjectPosition(zoneName, draggingIndex.index, newPosition);
2025-03-27 18:04:16 +05:30
animationRef.current = null;
});
}
2025-03-31 18:22:40 +05:30
};
2025-03-27 18:04:16 +05:30
2025-03-31 18:22:40 +05:30
const handlePointerUp = async (event: React.PointerEvent<HTMLDivElement>) => {
try {
if (!draggingIndex || !offset) return;
const container = document.getElementById("real-time-vis-canvas");
2025-03-31 18:22:40 +05:30
if (!container) return;
const rect = container.getBoundingClientRect();
const relativeX = event.clientX - rect.left;
const relativeY = event.clientY - rect.top;
2025-03-31 18:22:40 +05:30
// Only now determine the final position strategy
const finalPosition = determinePosition(rect, relativeX, relativeY);
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
// Calculate final position using the new strategy
let finalY = 0;
let finalX = 0;
if (activeProp1 === "top") {
finalY = relativeY - offset[0];
} else {
finalY = rect.height - (relativeY + offset[0]);
}
2025-03-31 18:22:40 +05:30
if (activeProp2 === "left") {
finalX = relativeX - offset[1];
} else {
finalX = rect.width - (relativeX + offset[1]);
}
2025-03-31 18:22:40 +05:30
// Apply boundaries
finalX = Math.max(0, Math.min(rect.width - 50, finalX));
finalY = Math.max(0, Math.min(rect.height - 50, finalY));
const boundedPosition = {
...finalPosition,
[activeProp1]: finalY,
[activeProp2]: finalX,
};
// Save to backend
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
const response = await addingFloatingWidgets(zone.zoneId, organization, {
...zone.objects[draggingIndex.index],
position: boundedPosition,
});
if (response.message === "Widget updated successfully") {
2025-03-31 18:22:40 +05:30
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
}
2025-03-31 18:22:40 +05:30
// Clean up
setDraggingIndex(null);
setOffset(null);
2025-03-31 18:22:40 +05:30
setActiveEdges(null); // Clear active edges
setCurrentPosition(null); // Reset current position
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
animationRef.current = null;
}
} catch (error) {
2025-03-31 18:22:40 +05:30
console.error("Error in handlePointerUp:", error);
2025-03-27 18:04:16 +05:30
}
2025-03-31 18:22:40 +05:30
};
2025-03-27 12:28:17 +05:30
2025-03-31 18:22:40 +05:30
const handleKebabClick = (id: string, event: React.MouseEvent) => {
event.stopPropagation();
setOpenKebabId((prevId) => (prevId === id ? null : id));
};
const renderObjectContent = (obj: any) => {
switch (obj.className) {
case "floating total-card":
return (
<>
<div className="header-wrapper">
<div className="header">{obj.header}</div>
<div className="data-values">
<div className="value">{obj.value}</div>
<div className="per">{obj.per}</div>
</div>
</div>
<div className="icon">
<WalletIcon />
</div>
</>
);
case "warehouseThroughput floating":
return (
<>
<div className="header">
<h2>Warehouse Throughput</h2>
<p>
<span>(+5) more</span> in 2025
</p>
</div>
<div className="lineGraph" style={{ height: "100%" }}>
{/* <Line data={lineGraphData} options={lineGraphOptions} /> */}
</div>
</>
);
case "fleetEfficiency floating":
return (
<>
<h2 className="header">Fleet Efficiency</h2>
<div className="progressContainer">
<div className="progress">
<div className="barOverflow">
<div
className="bar"
style={{ transform: `rotate(${obj.value}deg)` }}
></div>
</div>
</div>
</div>
<div className="scaleLabels">
<span>0%</span>
<div className="centerText">
<div className="percentage">{obj.per}%</div>
<div className="status">Optimal</div>
</div>
<span>100%</span>
</div>
</>
);
default:
return null;
}
};
2025-03-27 18:04:16 +05:30
return (
2025-03-31 18:22:40 +05:30
<div
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
className="floating-wrapper"
>
2025-03-27 18:04:16 +05:30
{zone.objects.map((obj, index) => (
<div
key={`${zoneName}-${index}`}
className={obj.className}
style={{
position: "absolute",
top:
2025-03-31 18:22:40 +05:30
typeof obj.position.top === "number"
? `${obj.position.top}px`
: "auto",
left:
2025-03-31 18:22:40 +05:30
typeof obj.position.left === "number"
? `${obj.position.left}px`
: "auto",
right:
2025-03-31 18:22:40 +05:30
typeof obj.position.right === "number"
? `${obj.position.right}px`
: "auto",
bottom:
2025-03-31 18:22:40 +05:30
typeof obj.position.bottom === "number"
? `${obj.position.bottom}px`
: "auto",
2025-03-27 18:04:16 +05:30
}}
onPointerDown={(event) => handlePointerDown(event, index)}
>
2025-03-31 18:22:40 +05:30
{renderObjectContent(obj)}
<div
className="icon kebab"
onClick={(event) => handleKebabClick(obj.id, event)}
>
<KebabIcon />
</div>
{openKebabId === obj.id && (
<div className="kebab-options">
<div className="dublicate btn">
<div className="icon">
<DublicateIcon />
2025-03-27 18:04:16 +05:30
</div>
2025-03-31 18:22:40 +05:30
<div className="label">Duplicate</div>
2025-03-27 18:04:16 +05:30
</div>
2025-03-31 18:22:40 +05:30
<div className="edit btn">
<div className="icon">
<DeleteIcon />
2025-03-27 18:04:16 +05:30
</div>
2025-03-31 18:22:40 +05:30
<div className="label">Delete</div>
2025-03-27 18:04:16 +05:30
</div>
2025-03-31 18:22:40 +05:30
</div>
)}
2025-03-27 18:04:16 +05:30
</div>
))}
2025-03-31 18:22:40 +05:30
{/* Render DistanceLines component during drag */}
{draggingIndex !== null &&
activeEdges !== null &&
currentPosition !== null && (
<DistanceLines
obj={{
position: {
top:
currentPosition.top !== "auto"
? currentPosition.top
: undefined,
bottom:
currentPosition.bottom !== "auto"
? currentPosition.bottom
: undefined,
left:
currentPosition.left !== "auto"
? currentPosition.left
: undefined,
right:
currentPosition.right !== "auto"
? currentPosition.right
: undefined,
},
}}
activeEdges={activeEdges}
/>
)}
2025-03-27 18:04:16 +05:30
</div>
);
};
2025-03-27 12:28:17 +05:30
2025-03-27 18:04:16 +05:30
export default DroppedObjects;
2025-03-31 18:22:40 +05:30
// in pointer move even when i goes to top right the value not changes to top right same problem in bottom left