bug fix
This commit is contained in:
parent
ba215dd0d3
commit
5066638782
|
@ -258,7 +258,11 @@ const MultiLevelDropdown = ({
|
||||||
</button>
|
</button>
|
||||||
{open && (
|
{open && (
|
||||||
<div className="dropdown-menu">
|
<div className="dropdown-menu">
|
||||||
<div className="dropdown-content">
|
<div className="dropdown-content ">
|
||||||
|
{/* loading list */}
|
||||||
|
|
||||||
|
{/* <div className="loading" /> */}
|
||||||
|
|
||||||
{/* Unselect Option */}
|
{/* Unselect Option */}
|
||||||
<DropdownItem label="Unselect" onClick={handleItemUnselect} />
|
<DropdownItem label="Unselect" onClick={handleItemUnselect} />
|
||||||
{/* Nested Dropdown Items */}
|
{/* Nested Dropdown Items */}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import MeasurementTool from "./tools/measurementTool";
|
||||||
import Simulation from "../simulation/simulation";
|
import Simulation from "../simulation/simulation";
|
||||||
|
|
||||||
// import Simulation from "./simulationtemp/simulation";
|
// import Simulation from "./simulationtemp/simulation";
|
||||||
import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget";
|
import ZoneCentreTarget from "../visualization/functions/zoneCameraTarget";
|
||||||
import Dropped3dWidgets from "../../modules/visualization/widgets/3d/Dropped3dWidget";
|
import Dropped3dWidgets from "../../modules/visualization/widgets/3d/Dropped3dWidget";
|
||||||
import ZoneAssets from "../visualization/zoneAssets";
|
import ZoneAssets from "../visualization/zoneAssets";
|
||||||
|
|
||||||
|
|
|
@ -97,11 +97,16 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
if (container) {
|
if (container) {
|
||||||
const isOverflowing = container.scrollWidth > container.clientWidth;
|
const isOverflowing = container.scrollWidth > container.clientWidth;
|
||||||
const canScrollLeft = container.scrollLeft > 0;
|
const canScrollLeft = container.scrollLeft > 0;
|
||||||
const canScrollRight =
|
|
||||||
container.scrollLeft + container.clientWidth < container.scrollWidth;
|
|
||||||
|
|
||||||
|
const canScrollRight =
|
||||||
|
container.scrollLeft + container.clientWidth + 1 <
|
||||||
|
container.scrollWidth;
|
||||||
setShowLeftArrow(isOverflowing && canScrollLeft);
|
setShowLeftArrow(isOverflowing && canScrollLeft);
|
||||||
setShowRightArrow(isOverflowing && canScrollRight);
|
setShowRightArrow(isOverflowing && canScrollRight);
|
||||||
|
|
||||||
|
console.log('canScrollRight: ', canScrollRight);
|
||||||
|
console.log('isOverflowing: ', isOverflowing);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -166,7 +171,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||||
if (selectedZone?.zoneId === zoneId) {
|
if (selectedZone?.zoneId === zoneId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSelectedChartId(null);
|
// setSelectedChartId(null);
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
let response = await getSelect2dZoneData(zoneId, organization);
|
let response = await getSelect2dZoneData(zoneId, organization);
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
import Dropped3dWidgets from "./widgets/3d/Dropped3dWidget";
|
import Dropped3dWidgets from "./widgets/3d/Dropped3dWidget";
|
||||||
import OuterClick from "../../utils/outerClick";
|
import OuterClick from "../../utils/outerClick";
|
||||||
import { useWidgetStore } from "../../store/useWidgetStore";
|
import { useWidgetStore } from "../../store/useWidgetStore";
|
||||||
|
import { getActiveProperties } from "./functions/getActiveProperties";
|
||||||
|
|
||||||
type Side = "top" | "bottom" | "left" | "right";
|
type Side = "top" | "bottom" | "left" | "right";
|
||||||
|
|
||||||
|
@ -166,60 +167,65 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const canvasElement = document.getElementById("real-time-vis-canvas");
|
const canvasElement = document.getElementById("real-time-vis-canvas");
|
||||||
if (!canvasElement) throw new Error("Canvas element not found");
|
if (!canvasElement) throw new Error("Canvas element not found");
|
||||||
|
|
||||||
// Get canvas dimensions and mouse position
|
|
||||||
const rect = canvasElement.getBoundingClientRect();
|
const rect = canvasElement.getBoundingClientRect();
|
||||||
let relativeX = (event.clientX - rect.left) ;
|
const relativeX = event.clientX - rect.left;
|
||||||
let relativeY = event.clientY - rect.top;
|
const relativeY = event.clientY - rect.top;
|
||||||
|
|
||||||
// Widget dimensions (with defaults)
|
// Widget dimensions
|
||||||
const widgetWidth = droppedData.width || 125; // 250/2 as default
|
const widgetWidth = droppedData.width || 125;
|
||||||
const widgetHeight = droppedData.height || 100; // 83/2 as default
|
const widgetHeight = droppedData.height || 100;
|
||||||
|
|
||||||
// Clamp to ensure widget stays fully inside canvas
|
// Center the widget at cursor
|
||||||
const clampedX = Math.max(
|
const centerOffsetX = widgetWidth / 2;
|
||||||
0, // Prevent going beyond left edge
|
const centerOffsetY = widgetHeight / 2;
|
||||||
Math.min(
|
|
||||||
relativeX,
|
|
||||||
rect.width - widgetWidth // Prevent going beyond right edge
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log('clampedX: ', clampedX);
|
|
||||||
const clampedY = Math.max(
|
|
||||||
0, // Prevent going beyond top edge
|
|
||||||
Math.min(
|
|
||||||
relativeY,
|
|
||||||
rect.height - widgetHeight // Prevent going beyond bottom edge
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Debug logging (optional)
|
const adjustedX = relativeX - centerOffsetX;
|
||||||
console.log("Drop coordinates:", {
|
const adjustedY = relativeY - centerOffsetY;
|
||||||
rawX: relativeX,
|
|
||||||
rawY: relativeY,
|
|
||||||
clampedX,
|
|
||||||
clampedY,
|
|
||||||
canvasWidth: rect.width,
|
|
||||||
canvasHeight: rect.height,
|
|
||||||
widgetWidth,
|
|
||||||
widgetHeight
|
|
||||||
});
|
|
||||||
|
|
||||||
const finalPosition = determinePosition(rect, clampedX, clampedY);
|
const finalPosition = determinePosition(rect, adjustedX, adjustedY);
|
||||||
|
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
||||||
|
|
||||||
|
let finalY = 0;
|
||||||
|
let finalX = 0;
|
||||||
|
|
||||||
|
if (activeProp1 === "top") {
|
||||||
|
finalY = adjustedY;
|
||||||
|
} else {
|
||||||
|
finalY = rect.height - (adjustedY + widgetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeProp2 === "left") {
|
||||||
|
finalX = adjustedX;
|
||||||
|
} else {
|
||||||
|
finalX = rect.width - (adjustedX + widgetWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp to boundaries
|
||||||
|
finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX));
|
||||||
|
finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY));
|
||||||
|
|
||||||
|
const boundedPosition = {
|
||||||
|
...finalPosition,
|
||||||
|
[activeProp1]: finalY,
|
||||||
|
[activeProp2]: finalX,
|
||||||
|
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
|
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
|
};
|
||||||
|
|
||||||
const newObject = {
|
const newObject = {
|
||||||
...droppedData,
|
...droppedData,
|
||||||
id: generateUniqueId(),
|
id: generateUniqueId(),
|
||||||
position: finalPosition,
|
position: boundedPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zone management
|
const existingZone =
|
||||||
const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
||||||
if (!existingZone) {
|
if (!existingZone) {
|
||||||
useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId);
|
useDroppedObjectsStore
|
||||||
|
.getState()
|
||||||
|
.setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Socket emission
|
|
||||||
const addFloatingWidget = {
|
const addFloatingWidget = {
|
||||||
organization,
|
organization,
|
||||||
widget: newObject,
|
widget: newObject,
|
||||||
|
@ -230,25 +236,27 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store update
|
useDroppedObjectsStore
|
||||||
useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, newObject);
|
.getState()
|
||||||
|
.addObject(selectedZone.zoneName, newObject);
|
||||||
|
|
||||||
// Post-drop verification
|
|
||||||
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
||||||
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
||||||
|
|
||||||
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
||||||
console.log(`Objects for Zone ${selectedZone.zoneId}:`, currentZone.objects);
|
console.log(
|
||||||
|
`Objects for Zone ${selectedZone.zoneId}:`,
|
||||||
|
currentZone.objects
|
||||||
|
);
|
||||||
setFloatingWidget(currentZone.objects);
|
setFloatingWidget(currentZone.objects);
|
||||||
} else {
|
} else {
|
||||||
console.warn("Zone not found or zoneId mismatch");
|
console.warn("Zone not found or zoneId mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in handleDrop:", error);
|
console.error("Error in handleDrop:", error);
|
||||||
// Consider adding user feedback here (e.g., toast notification)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
@ -270,8 +278,42 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
};
|
};
|
||||||
}, [setRightClickSelected]);
|
}, [setRightClickSelected]);
|
||||||
|
|
||||||
|
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvas) return;
|
||||||
|
|
||||||
|
const updateCanvasDimensions = () => {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
setCanvasDimensions({
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
updateCanvasDimensions();
|
||||||
|
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
|
||||||
|
resizeObserver.observe(canvas);
|
||||||
|
|
||||||
|
return () => resizeObserver.unobserve(canvas);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
:root {
|
||||||
|
--realTimeViz-container-width: ${canvasDimensions.width}px;
|
||||||
|
|
||||||
|
--realTimeViz-container-height: ${canvasDimensions.height}px;
|
||||||
|
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
id="real-time-vis-canvas"
|
id="real-time-vis-canvas"
|
||||||
|
|
|
@ -1,94 +1,94 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { Bar } from "react-chartjs-2";
|
import { Bar } from "react-chartjs-2";
|
||||||
|
|
||||||
interface ChartComponentProps {
|
interface ChartComponentProps {
|
||||||
type: any;
|
type: any;
|
||||||
title: string;
|
title: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontWeight?: "Light" | "Regular" | "Bold";
|
fontWeight?: "Light" | "Regular" | "Bold";
|
||||||
data: any;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LineGraphComponent = ({
|
const LineGraphComponent = ({
|
||||||
title,
|
title,
|
||||||
fontFamily,
|
fontFamily,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight = "Regular",
|
fontWeight = "Regular",
|
||||||
}: ChartComponentProps) => {
|
}: ChartComponentProps) => {
|
||||||
// Memoize Font Weight Mapping
|
// Memoize Font Weight Mapping
|
||||||
const chartFontWeightMap = useMemo(
|
const chartFontWeightMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
Light: "lighter" as const,
|
Light: "lighter" as const,
|
||||||
Regular: "normal" as const,
|
Regular: "normal" as const,
|
||||||
Bold: "bold" as const,
|
Bold: "bold" as const,
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse and Memoize Font Size
|
// Parse and Memoize Font Size
|
||||||
const fontSizeValue = useMemo(
|
const fontSizeValue = useMemo(
|
||||||
() => (fontSize ? parseInt(fontSize) : 12),
|
() => (fontSize ? parseInt(fontSize) : 12),
|
||||||
[fontSize]
|
[fontSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine and Memoize Font Weight
|
// Determine and Memoize Font Weight
|
||||||
const fontWeightValue = useMemo(
|
const fontWeightValue = useMemo(
|
||||||
() => chartFontWeightMap[fontWeight],
|
() => chartFontWeightMap[fontWeight],
|
||||||
[fontWeight, chartFontWeightMap]
|
[fontWeight, chartFontWeightMap]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize Chart Font Style
|
// Memoize Chart Font Style
|
||||||
const chartFontStyle = useMemo(
|
const chartFontStyle = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
family: fontFamily || "Arial",
|
family: fontFamily || "Arial",
|
||||||
size: fontSizeValue,
|
size: fontSizeValue,
|
||||||
weight: fontWeightValue,
|
weight: fontWeightValue,
|
||||||
}),
|
}),
|
||||||
[fontFamily, fontSizeValue, fontWeightValue]
|
[fontFamily, fontSizeValue, fontWeightValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: title,
|
text: title,
|
||||||
font: chartFontStyle,
|
font: chartFontStyle,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
ticks: {
|
ticks: {
|
||||||
display: false, // This hides the x-axis labels
|
display: false, // This hides the x-axis labels
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[title, chartFontStyle]
|
[title, chartFontStyle]
|
||||||
);
|
);
|
||||||
|
|
||||||
const chartData = {
|
const chartData = {
|
||||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "My First Dataset",
|
label: "My First Dataset",
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
backgroundColor: "#6f42c1",
|
backgroundColor: "#6f42c1",
|
||||||
borderColor: "#ffffff",
|
borderColor: "#ffffff",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
fill: false,
|
fill: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Bar data={chartData} options={options} />;
|
return <Bar data={chartData} options={options} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LineGraphComponent;
|
export default LineGraphComponent;
|
|
@ -1,93 +1,93 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Line } from "react-chartjs-2";
|
import { Line } from "react-chartjs-2";
|
||||||
|
|
||||||
interface ChartComponentProps {
|
interface ChartComponentProps {
|
||||||
type: any;
|
type: any;
|
||||||
title: string;
|
title: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontWeight?: "Light" | "Regular" | "Bold";
|
fontWeight?: "Light" | "Regular" | "Bold";
|
||||||
data: any;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LineGraphComponent = ({
|
const LineGraphComponent = ({
|
||||||
title,
|
title,
|
||||||
fontFamily,
|
fontFamily,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight = "Regular",
|
fontWeight = "Regular",
|
||||||
}: ChartComponentProps) => {
|
}: ChartComponentProps) => {
|
||||||
// Memoize Font Weight Mapping
|
// Memoize Font Weight Mapping
|
||||||
const chartFontWeightMap = useMemo(
|
const chartFontWeightMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
Light: "lighter" as const,
|
Light: "lighter" as const,
|
||||||
Regular: "normal" as const,
|
Regular: "normal" as const,
|
||||||
Bold: "bold" as const,
|
Bold: "bold" as const,
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse and Memoize Font Size
|
// Parse and Memoize Font Size
|
||||||
const fontSizeValue = useMemo(
|
const fontSizeValue = useMemo(
|
||||||
() => (fontSize ? parseInt(fontSize) : 12),
|
() => (fontSize ? parseInt(fontSize) : 12),
|
||||||
[fontSize]
|
[fontSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine and Memoize Font Weight
|
// Determine and Memoize Font Weight
|
||||||
const fontWeightValue = useMemo(
|
const fontWeightValue = useMemo(
|
||||||
() => chartFontWeightMap[fontWeight],
|
() => chartFontWeightMap[fontWeight],
|
||||||
[fontWeight, chartFontWeightMap]
|
[fontWeight, chartFontWeightMap]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize Chart Font Style
|
// Memoize Chart Font Style
|
||||||
const chartFontStyle = useMemo(
|
const chartFontStyle = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
family: fontFamily || "Arial",
|
family: fontFamily || "Arial",
|
||||||
size: fontSizeValue,
|
size: fontSizeValue,
|
||||||
weight: fontWeightValue,
|
weight: fontWeightValue,
|
||||||
}),
|
}),
|
||||||
[fontFamily, fontSizeValue, fontWeightValue]
|
[fontFamily, fontSizeValue, fontWeightValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: title,
|
text: title,
|
||||||
font: chartFontStyle,
|
font: chartFontStyle,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
x: {
|
x: {
|
||||||
ticks: {
|
ticks: {
|
||||||
display: false, // This hides the x-axis labels
|
display: false, // This hides the x-axis labels
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[title, chartFontStyle]
|
[title, chartFontStyle]
|
||||||
);
|
);
|
||||||
|
|
||||||
const chartData = {
|
const chartData = {
|
||||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "My First Dataset",
|
label: "My First Dataset",
|
||||||
data: [65, 59, 80, 81, 56, 55, 40],
|
data: [65, 59, 80, 81, 56, 55, 40],
|
||||||
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
|
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
|
||||||
borderColor: "#ffffff", // Keeping border color white
|
borderColor: "#ffffff", // Keeping border color white
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
fill: false,
|
fill: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Line data={chartData} options={options} />;
|
return <Line data={chartData} options={options} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LineGraphComponent;
|
export default LineGraphComponent;
|
|
@ -1,90 +1,90 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Pie } from "react-chartjs-2";
|
import { Pie } from "react-chartjs-2";
|
||||||
|
|
||||||
interface ChartComponentProps {
|
interface ChartComponentProps {
|
||||||
type: any;
|
type: any;
|
||||||
title: string;
|
title: string;
|
||||||
fontFamily?: string;
|
fontFamily?: string;
|
||||||
fontSize?: string;
|
fontSize?: string;
|
||||||
fontWeight?: "Light" | "Regular" | "Bold";
|
fontWeight?: "Light" | "Regular" | "Bold";
|
||||||
data: any;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PieChartComponent = ({
|
const PieChartComponent = ({
|
||||||
title,
|
title,
|
||||||
fontFamily,
|
fontFamily,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight = "Regular",
|
fontWeight = "Regular",
|
||||||
}: ChartComponentProps) => {
|
}: ChartComponentProps) => {
|
||||||
// Memoize Font Weight Mapping
|
// Memoize Font Weight Mapping
|
||||||
const chartFontWeightMap = useMemo(
|
const chartFontWeightMap = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
Light: "lighter" as const,
|
Light: "lighter" as const,
|
||||||
Regular: "normal" as const,
|
Regular: "normal" as const,
|
||||||
Bold: "bold" as const,
|
Bold: "bold" as const,
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Parse and Memoize Font Size
|
// Parse and Memoize Font Size
|
||||||
const fontSizeValue = useMemo(
|
const fontSizeValue = useMemo(
|
||||||
() => (fontSize ? parseInt(fontSize) : 12),
|
() => (fontSize ? parseInt(fontSize) : 12),
|
||||||
[fontSize]
|
[fontSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Determine and Memoize Font Weight
|
// Determine and Memoize Font Weight
|
||||||
const fontWeightValue = useMemo(
|
const fontWeightValue = useMemo(
|
||||||
() => chartFontWeightMap[fontWeight],
|
() => chartFontWeightMap[fontWeight],
|
||||||
[fontWeight, chartFontWeightMap]
|
[fontWeight, chartFontWeightMap]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Memoize Chart Font Style
|
// Memoize Chart Font Style
|
||||||
const chartFontStyle = useMemo(
|
const chartFontStyle = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
family: fontFamily || "Arial",
|
family: fontFamily || "Arial",
|
||||||
size: fontSizeValue,
|
size: fontSizeValue,
|
||||||
weight: fontWeightValue,
|
weight: fontWeightValue,
|
||||||
}),
|
}),
|
||||||
[fontFamily, fontSizeValue, fontWeightValue]
|
[fontFamily, fontSizeValue, fontWeightValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Access the CSS variable for the primary accent color
|
// Access the CSS variable for the primary accent color
|
||||||
const accentColor = getComputedStyle(document.documentElement)
|
const accentColor = getComputedStyle(document.documentElement)
|
||||||
.getPropertyValue("--accent-color")
|
.getPropertyValue("--accent-color")
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: title,
|
text: title,
|
||||||
font: chartFontStyle,
|
font: chartFontStyle,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[title, chartFontStyle]
|
[title, chartFontStyle]
|
||||||
);
|
);
|
||||||
|
|
||||||
const chartData = {
|
const chartData = {
|
||||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Dataset",
|
label: "Dataset",
|
||||||
data: [12, 19, 3, 5, 2, 3],
|
data: [12, 19, 3, 5, 2, 3],
|
||||||
backgroundColor: ["#6f42c1"],
|
backgroundColor: ["#6f42c1"],
|
||||||
borderColor: "#ffffff",
|
borderColor: "#ffffff",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Pie data={chartData} options={options} />;
|
return <Pie data={chartData} options={options} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PieChartComponent;
|
export default PieChartComponent;
|
|
@ -89,9 +89,7 @@ export const DraggableWidget = ({
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {}, [measurements, duration, name]);
|
||||||
console.log("changes loggggg", measurements, duration, name);
|
|
||||||
}, [measurements, duration, name])
|
|
||||||
const handlePointerDown = () => {
|
const handlePointerDown = () => {
|
||||||
if (selectedChartId?.id !== widget.id) {
|
if (selectedChartId?.id !== widget.id) {
|
||||||
setSelectedChartId(widget);
|
setSelectedChartId(widget);
|
||||||
|
@ -148,7 +146,7 @@ export const DraggableWidget = ({
|
||||||
const getCurrentWidgetCount = (panel: Side) =>
|
const getCurrentWidgetCount = (panel: Side) =>
|
||||||
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
selectedZone.widgets.filter((w) => w.panel === panel).length;
|
||||||
// Calculate panel capacity
|
// Calculate panel capacity
|
||||||
|
|
||||||
const calculatePanelCapacity = (panel: Side) => {
|
const calculatePanelCapacity = (panel: Side) => {
|
||||||
const CHART_WIDTH = panelSize;
|
const CHART_WIDTH = panelSize;
|
||||||
const CHART_HEIGHT = panelSize;
|
const CHART_HEIGHT = panelSize;
|
||||||
|
@ -167,25 +165,22 @@ export const DraggableWidget = ({
|
||||||
const currentWidgetCount = getCurrentWidgetCount(panel);
|
const currentWidgetCount = getCurrentWidgetCount(panel);
|
||||||
const panelCapacity = calculatePanelCapacity(panel);
|
const panelCapacity = calculatePanelCapacity(panel);
|
||||||
|
|
||||||
return currentWidgetCount > panelCapacity;
|
return currentWidgetCount > panelCapacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const duplicateWidget = async () => {
|
const duplicateWidget = async () => {
|
||||||
try {
|
try {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
console.log("widget data sent", widget);
|
|
||||||
|
|
||||||
|
|
||||||
const duplicatedWidget: Widget = {
|
const duplicatedWidget: Widget = {
|
||||||
...widget,
|
...widget,
|
||||||
Data: {
|
Data: {
|
||||||
duration: duration,
|
duration: duration,
|
||||||
measurements: { ...measurements }
|
measurements: { ...measurements },
|
||||||
},
|
},
|
||||||
id: `${widget.id}-copy-${Date.now()}`,
|
id: `${widget.id}-copy-${Date.now()}`,
|
||||||
};
|
};
|
||||||
console.log("duplicatedWidget: ", duplicatedWidget);
|
|
||||||
|
|
||||||
let duplicateWidget = {
|
let duplicateWidget = {
|
||||||
organization: organization,
|
organization: organization,
|
||||||
|
@ -193,8 +188,6 @@ export const DraggableWidget = ({
|
||||||
widget: duplicatedWidget,
|
widget: duplicatedWidget,
|
||||||
};
|
};
|
||||||
if (visualizationSocket) {
|
if (visualizationSocket) {
|
||||||
console.log("duplecate widget", duplicateWidget);
|
|
||||||
|
|
||||||
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
|
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
|
||||||
}
|
}
|
||||||
setSelectedZone((prevZone: any) => ({
|
setSelectedZone((prevZone: any) => ({
|
||||||
|
@ -293,20 +286,12 @@ export const DraggableWidget = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style>
|
|
||||||
{`
|
|
||||||
:root {
|
|
||||||
--realTimeViz-container-width: ${canvasDimensions.width}px;
|
|
||||||
--realTimeViz-container-height: ${canvasDimensions.height}px;
|
|
||||||
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
</style>
|
|
||||||
<div
|
<div
|
||||||
draggable
|
draggable
|
||||||
key={widget.id}
|
key={widget.id}
|
||||||
className={`chart-container ${selectedChartId?.id === widget.id && !isPlaying && "activeChart"
|
className={`chart-container ${
|
||||||
}`}
|
selectedChartId?.id === widget.id && !isPlaying && "activeChart"
|
||||||
|
}`}
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
onDragEnter={handleDragEnter}
|
onDragEnter={handleDragEnter}
|
||||||
|
@ -317,7 +302,7 @@ export const DraggableWidget = ({
|
||||||
? `calc(${canvasDimensions.width}px / 6)`
|
? `calc(${canvasDimensions.width}px / 6)`
|
||||||
: undefined,
|
: undefined,
|
||||||
height: ["left", "right"].includes(widget.panel)
|
height: ["left", "right"].includes(widget.panel)
|
||||||
? `calc(${canvasDimensions.height - 10}px / 4)`
|
? `calc(${canvasDimensions.height - 15}px / 4)`
|
||||||
: undefined,
|
: undefined,
|
||||||
}}
|
}}
|
||||||
ref={chartWidget}
|
ref={chartWidget}
|
||||||
|
@ -332,8 +317,9 @@ export const DraggableWidget = ({
|
||||||
{openKebabId === widget.id && (
|
{openKebabId === widget.id && (
|
||||||
<div className="kebab-options" ref={widgetRef}>
|
<div className="kebab-options" ref={widgetRef}>
|
||||||
<div
|
<div
|
||||||
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : ""
|
className={`edit btn ${
|
||||||
}`}
|
isPanelFull(widget.panel) ? "btn-blur" : ""
|
||||||
|
}`}
|
||||||
onClick={duplicateWidget}
|
onClick={duplicateWidget}
|
||||||
>
|
>
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
|
|
|
@ -238,7 +238,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({
|
||||||
rotation={rotation}
|
rotation={rotation}
|
||||||
scale={[0.5, 0.5, 0.5]}
|
scale={[0.5, 0.5, 0.5]}
|
||||||
transform
|
transform
|
||||||
zIndexRange={[1, 0]}
|
|
||||||
sprite={false}
|
sprite={false}
|
||||||
// style={{
|
// style={{
|
||||||
// transform: transformStyle.transform,
|
// transform: transformStyle.transform,
|
||||||
|
|
|
@ -121,10 +121,12 @@ const DroppedObjects: React.FC = () => {
|
||||||
function handleDuplicate(zoneName: string, index: number) {
|
function handleDuplicate(zoneName: string, index: number) {
|
||||||
setOpenKebabId(null);
|
setOpenKebabId(null);
|
||||||
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
duplicateObject(zoneName, index); // Call the duplicateObject method from the store
|
||||||
|
setSelectedChartId(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDelete(zoneName: string, id: string) {
|
async function handleDelete(zoneName: string, id: string) {
|
||||||
try {
|
try {
|
||||||
|
setSelectedChartId(null);
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
|
@ -532,7 +534,7 @@ const DroppedObjects: React.FC = () => {
|
||||||
typeof obj.position.left === "number"
|
typeof obj.position.left === "number"
|
||||||
? `calc(${obj.position.left}px + ${
|
? `calc(${obj.position.left}px + ${
|
||||||
isPlaying && selectedZone.activeSides.includes("left")
|
isPlaying && selectedZone.activeSides.includes("left")
|
||||||
? `${widthMultiplier - 100}px`
|
? `${widthMultiplier - 150}px`
|
||||||
: "0px"
|
: "0px"
|
||||||
})`
|
})`
|
||||||
: "auto";
|
: "auto";
|
||||||
|
@ -541,11 +543,10 @@ const DroppedObjects: React.FC = () => {
|
||||||
typeof obj.position.right === "number"
|
typeof obj.position.right === "number"
|
||||||
? `calc(${obj.position.right}px + ${
|
? `calc(${obj.position.right}px + ${
|
||||||
isPlaying && selectedZone.activeSides.includes("right")
|
isPlaying && selectedZone.activeSides.includes("right")
|
||||||
? `${widthMultiplier - 100}px`
|
? `${widthMultiplier - 150}px`
|
||||||
: "0px"
|
: "0px"
|
||||||
})`
|
})`
|
||||||
: "auto";
|
: "auto";
|
||||||
|
|
||||||
const bottomPosition =
|
const bottomPosition =
|
||||||
typeof obj.position.bottom === "number"
|
typeof obj.position.bottom === "number"
|
||||||
? `calc(${obj.position.bottom}px + ${
|
? `calc(${obj.position.bottom}px + ${
|
||||||
|
@ -663,4 +664,3 @@ const DroppedObjects: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DroppedObjects;
|
export default DroppedObjects;
|
||||||
|
|
||||||
|
|
|
@ -1,113 +1,117 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from "react";
|
||||||
import { Line } from 'react-chartjs-2'
|
import { Line } from "react-chartjs-2";
|
||||||
import useChartStore from '../../../../../store/useChartStore';
|
import useChartStore from "../../../../../store/useChartStore";
|
||||||
import { useWidgetStore } from '../../../../../store/useWidgetStore';
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
import axios from 'axios';
|
import axios from "axios";
|
||||||
import io from "socket.io-client";
|
import io from "socket.io-client";
|
||||||
|
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||||
|
|
||||||
const FleetEfficiencyComponent = ({object}: any) => {
|
const FleetEfficiencyComponent = ({ object }: any) => {
|
||||||
const [ progress, setProgress ] = useState<any>(0)
|
const [progress, setProgress] = useState<any>(0);
|
||||||
const [measurements, setmeasurements] = useState<any>({});
|
const [measurements, setmeasurements] = useState<any>({});
|
||||||
const [duration, setDuration] = useState("1h")
|
const [duration, setDuration] = useState("1h");
|
||||||
const [name, setName] = useState(object.header ? object.header : '')
|
const [name, setName] = useState(object.header ? object.header : "");
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0]
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
||||||
const { selectedChartId } = useWidgetStore();
|
const { selectedChartId } = useWidgetStore();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||||
|
|
||||||
// Calculate the rotation angle for the progress bar
|
// Calculate the rotation angle for the progress bar
|
||||||
const rotationAngle = 45 + progress * 1.8;
|
const rotationAngle = 45 + progress * 1.8;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0)
|
||||||
|
return;
|
||||||
|
|
||||||
useEffect(() => {
|
const socket = io(`http://${iotApiUrl}`);
|
||||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
|
||||||
|
const inputData = {
|
||||||
const socket = io(`http://${iotApiUrl}`);
|
measurements,
|
||||||
|
duration,
|
||||||
const inputData = {
|
interval: 1000,
|
||||||
measurements,
|
};
|
||||||
duration,
|
|
||||||
interval: 1000,
|
const startStream = () => {
|
||||||
};
|
socket.emit("lastInput", inputData);
|
||||||
|
};
|
||||||
|
|
||||||
const startStream = () => {
|
socket.on("connect", startStream);
|
||||||
socket.emit("lastInput", inputData);
|
|
||||||
};
|
socket.on("lastOutput", (response) => {
|
||||||
|
const responseData = response.input1;
|
||||||
socket.on("connect", startStream);
|
// console.log(responseData);
|
||||||
|
|
||||||
socket.on("lastOutput", (response) => {
|
if (typeof responseData === "number") {
|
||||||
const responseData = response.input1;
|
console.log("It's a number!");
|
||||||
// console.log(responseData);
|
setProgress(responseData);
|
||||||
|
|
||||||
if (typeof responseData === "number") {
|
|
||||||
console.log("It's a number!");
|
|
||||||
setProgress(responseData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
socket.off("lastOutput");
|
|
||||||
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
|
||||||
socket.disconnect();
|
|
||||||
};
|
|
||||||
}, [measurements, duration, iotApiUrl]);
|
|
||||||
|
|
||||||
const fetchSavedInputes = async() => {
|
|
||||||
|
|
||||||
if (object?.id !== "") {
|
|
||||||
try {
|
|
||||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`);
|
|
||||||
if (response.status === 200) {
|
|
||||||
setmeasurements(response.data.Data.measurements)
|
|
||||||
setDuration(response.data.Data.duration)
|
|
||||||
setName(response.data.header)
|
|
||||||
} else {
|
|
||||||
console.log("Unexpected response:", response);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("There was an error!", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
useEffect(() => {
|
|
||||||
fetchSavedInputes();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selectedChartId?.id === object?.id) {
|
|
||||||
fetchSavedInputes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,[header, flotingDuration, flotingMeasurements])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h2 className="header">{name}</h2>
|
|
||||||
<div className="progressContainer">
|
|
||||||
<div className="progress">
|
|
||||||
<div className="barOverflow">
|
|
||||||
<div
|
|
||||||
className="bar"
|
|
||||||
style={{ transform: `rotate(${rotationAngle}deg)` }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="scaleLabels">
|
|
||||||
<span>0%</span>
|
|
||||||
<div className="centerText">
|
|
||||||
<div className="percentage">{progress}%</div>
|
|
||||||
<div className="status">Optimal</div>
|
|
||||||
</div>
|
|
||||||
<span>100%</span>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FleetEfficiencyComponent
|
return () => {
|
||||||
|
socket.off("lastOutput");
|
||||||
|
socket.emit("stop_stream"); // Stop streaming when component unmounts
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [measurements, duration, iotApiUrl]);
|
||||||
|
|
||||||
|
const fetchSavedInputes = async () => {
|
||||||
|
if (object?.id !== "") {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(
|
||||||
|
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`
|
||||||
|
);
|
||||||
|
if (response.status === 200) {
|
||||||
|
setmeasurements(response.data.Data.measurements);
|
||||||
|
setDuration(response.data.Data.duration);
|
||||||
|
setName(response.data.header);
|
||||||
|
} else {
|
||||||
|
console.log("Unexpected response:", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("There was an error!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedChartId?.id === object?.id) {
|
||||||
|
fetchSavedInputes();
|
||||||
|
}
|
||||||
|
}, [header, flotingDuration, flotingMeasurements]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2 className="header">{name}</h2>
|
||||||
|
<div
|
||||||
|
className="progressContainer"
|
||||||
|
style={{ transform: isPlaying ? "skew(-14deg, 0deg)" : "none" }}
|
||||||
|
>
|
||||||
|
<div className="progress">
|
||||||
|
<div className="barOverflow">
|
||||||
|
<div
|
||||||
|
className="bar"
|
||||||
|
style={{ transform: `rotate(${rotationAngle}deg)` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="scaleLabels">
|
||||||
|
<span>0%</span>
|
||||||
|
<div className="centerText">
|
||||||
|
<div className="percentage">{progress}%</div>
|
||||||
|
<div className="status">Optimal</div>
|
||||||
|
</div>
|
||||||
|
<span>100%</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FleetEfficiencyComponent;
|
||||||
|
|
|
@ -128,6 +128,12 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
const cleanPanel = async (side: Side) => {
|
const cleanPanel = async (side: Side) => {
|
||||||
//add api
|
//add api
|
||||||
// console.log('side: ', side);
|
// console.log('side: ', side);
|
||||||
|
if (
|
||||||
|
hiddenPanels[selectedZone.zoneId]?.includes(side) ||
|
||||||
|
selectedZone.lockedPanels.includes(side)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") || "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||||
|
|
||||||
|
@ -197,13 +203,12 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
}
|
}
|
||||||
setSelectedZone(updatedZone);
|
setSelectedZone(updatedZone);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (hiddenPanels[selectedZone.zoneId]?.includes(side)) {
|
if (hiddenPanels[selectedZone.zoneId]?.includes(side)) {
|
||||||
|
setHiddenPanels((prev) => ({
|
||||||
setHiddenPanels(prev => ({
|
|
||||||
...prev,
|
...prev,
|
||||||
[selectedZone.zoneId]: prev[selectedZone.zoneId].filter(s => s !== side)
|
[selectedZone.zoneId]: prev[selectedZone.zoneId].filter(
|
||||||
|
(s) => s !== side
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,10 +289,11 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
<div className="extra-Bs">
|
<div className="extra-Bs">
|
||||||
{/* Hide Panel */}
|
{/* Hide Panel */}
|
||||||
<div
|
<div
|
||||||
className={`icon ${hiddenPanels[selectedZone.zoneId]?.includes(side)
|
className={`icon ${
|
||||||
? "active"
|
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||||
: ""
|
? "active"
|
||||||
}`}
|
: ""
|
||||||
|
}`}
|
||||||
title={
|
title={
|
||||||
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
hiddenPanels[selectedZone.zoneId]?.includes(side)
|
||||||
? "Show Panel"
|
? "Show Panel"
|
||||||
|
@ -309,6 +315,13 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
||||||
className="icon"
|
className="icon"
|
||||||
title="Clean Panel"
|
title="Clean Panel"
|
||||||
onClick={() => cleanPanel(side)}
|
onClick={() => cleanPanel(side)}
|
||||||
|
style={{
|
||||||
|
cursor:
|
||||||
|
hiddenPanels[selectedZone.zoneId]?.includes(side) ||
|
||||||
|
selectedZone.lockedPanels.includes(side)
|
||||||
|
? "not-allowed"
|
||||||
|
: "pointer",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<CleanPannel />
|
<CleanPannel />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -344,6 +344,45 @@ input {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 2px;
|
||||||
|
/* slim progress bar */
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
/* optional track background */
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -50%;
|
||||||
|
height: 100%;
|
||||||
|
width: 50%;
|
||||||
|
background: linear-gradient(to right,
|
||||||
|
var(--accent-color),
|
||||||
|
transparent);
|
||||||
|
animation: loadingAnimation 1.2s linear infinite;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loadingAnimation {
|
||||||
|
0% {
|
||||||
|
left: -50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
|
|
|
@ -480,3 +480,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// progress should be progress {progress}
|
// progress should be progress {progress}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue