Dwinzo_dev/app/src/components/ui/componets/DisplayZone.tsx

234 lines
6.9 KiB
TypeScript
Raw Normal View History

2025-03-27 05:24:40 +00:00
import React, { useEffect, useRef, useState, useCallback } from "react";
2025-03-25 12:04:20 +00:00
import { Widget } from "../../../store/useWidgetStore";
import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons";
2025-03-27 12:40:49 +00:00
import { InfoIcon } from "../../icons/ExportCommonIcons";
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData";
import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData";
2025-03-25 12:04:20 +00:00
// Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right";
interface DisplayZoneProps {
zonesData: {
[key: string]: {
activeSides: Side[];
panelOrder: Side[];
2025-03-25 12:04:20 +00:00
lockedPanels: Side[];
widgets: Widget[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
2025-03-25 12:04:20 +00:00
};
};
selectedZone: {
zoneName: string;
activeSides: Side[];
panelOrder: Side[];
2025-03-25 12:04:20 +00:00
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
2025-03-25 12:04:20 +00:00
widgets: {
id: string;
type: string;
title: string;
panel: Side;
data: any;
}[];
};
setSelectedZone: React.Dispatch<
React.SetStateAction<{
zoneName: string;
activeSides: Side[];
panelOrder: Side[];
2025-03-25 12:04:20 +00:00
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
zoneViewPortPosition: number[];
2025-03-25 12:04:20 +00:00
widgets: {
id: string;
type: string;
title: string;
panel: Side;
data: any;
}[];
}>
>;
}
const DisplayZone: React.FC<DisplayZoneProps> = ({
zonesData,
selectedZone,
setSelectedZone,
}) => {
2025-03-25 12:04:20 +00:00
// Ref for the container element
const containerRef = useRef<HTMLDivElement | null>(null);
2025-03-27 05:24:40 +00:00
// State to track overflow visibility
const [showLeftArrow, setShowLeftArrow] = useState(false);
const [showRightArrow, setShowRightArrow] = useState(false);
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
// Function to calculate overflow state
const updateOverflowState = useCallback(() => {
2025-03-25 12:04:20 +00:00
const container = containerRef.current;
2025-03-27 05:24:40 +00:00
if (container) {
const isOverflowing = container.scrollWidth > container.clientWidth;
const canScrollLeft = container.scrollLeft > 0;
const canScrollRight =
container.scrollLeft + container.clientWidth < container.scrollWidth;
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
setShowLeftArrow(isOverflowing && canScrollLeft);
setShowRightArrow(isOverflowing && canScrollRight);
2025-03-25 12:04:20 +00:00
}
2025-03-27 05:24:40 +00:00
}, []);
2025-03-25 12:04:20 +00:00
useEffect(() => {
const container = containerRef.current;
2025-03-27 05:24:40 +00:00
if (container) {
// Initial calculation after the DOM has been rendered
const handleInitialRender = () => {
requestAnimationFrame(updateOverflowState);
};
handleInitialRender();
// Update on window resize or scroll
const handleResize = () => updateOverflowState();
const handleScroll = () => updateOverflowState();
// Add mouse wheel listener for horizontal scrolling
const handleWheel = (event: WheelEvent) => {
event.preventDefault(); // Prevent default vertical scrolling
if (container) {
container.scrollBy({
left: event.deltaY * 2, // Translate vertical scroll to horizontal scroll
behavior: "smooth",
});
}
};
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
container.addEventListener("scroll", handleScroll);
window.addEventListener("resize", handleResize);
container.addEventListener("wheel", handleWheel, { passive: false });
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
return () => {
container.removeEventListener("scroll", handleScroll);
window.removeEventListener("resize", handleResize);
container.removeEventListener("wheel", handleWheel);
};
}
}, [updateOverflowState]);
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
// Handle scrolling with navigation arrows
const handleScrollLeft = () => {
const container = containerRef.current;
2025-03-25 12:04:20 +00:00
if (container) {
2025-03-27 05:24:40 +00:00
container.scrollBy({
left: -200, // Scroll left by 200px
behavior: "smooth",
});
2025-03-25 12:04:20 +00:00
}
2025-03-27 05:24:40 +00:00
};
2025-03-25 12:04:20 +00:00
2025-03-27 05:24:40 +00:00
const handleScrollRight = () => {
const container = containerRef.current;
if (container) {
container.scrollBy({
left: 200, // Scroll right by 200px
behavior: "smooth",
});
}
2025-03-25 12:04:20 +00:00
};
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);
let res = await getFloatingZoneData(zoneId, organization);
// Set the selected zone in the store
useDroppedObjectsStore.getState().setZone(zoneName, zoneId);
if (Array.isArray(res)) {
res.forEach((val) => {
useDroppedObjectsStore.getState().addObject(zoneName, val);
});
}
// Update selected zone state
setSelectedZone({
zoneName,
activeSides: response.activeSides || [],
panelOrder: response.panelOrder || [],
lockedPanels: response.lockedPanels || [],
widgets: response.widgets || [],
zoneId: zoneId,
zoneViewPortTarget: response.viewPortCenter || {},
zoneViewPortPosition: response.viewPortposition || {},
});
} catch (error) {
console.log('error: ', error);
}
}
2025-03-25 12:04:20 +00:00
return (
2025-03-27 11:54:36 +00:00
<div
ref={containerRef}
2025-03-28 13:50:52 +00:00
className={`zone-wrapper ${
2025-03-27 11:54:36 +00:00
selectedZone?.activeSides?.includes("bottom") && "bottom"
}`}
>
2025-03-27 05:24:40 +00:00
{/* Left Arrow */}
{showLeftArrow && (
<button className="arrow left-arrow" onClick={handleScrollLeft}>
<MoveArrowLeft />
2025-03-27 05:24:40 +00:00
</button>
)}
{/* Zones Wrapper */}
{Object.keys(zonesData).length !== 0 ? (
<div ref={containerRef} className="zones-wrapper">
{Object.keys(zonesData).map((zoneName, index) => (
<div
key={index}
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""
}`}
onClick={() => {
handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName)
}}
>
{zoneName}
</div>
))}
</div>
) : (
<div className="no-zone">
<InfoIcon />
No zones? Create one!
2025-03-25 12:04:20 +00:00
</div>
)}
2025-03-27 05:24:40 +00:00
{/* Right Arrow */}
{showRightArrow && (
<button className="arrow right-arrow" onClick={handleScrollRight}>
<MoveArrowRight />
2025-03-27 05:24:40 +00:00
</button>
)}
2025-03-25 12:04:20 +00:00
</div>
);
};
export default DisplayZone;