diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx
index b99b297..5eb8d4e 100644
--- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx
+++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx
@@ -3,13 +3,10 @@ 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";
import { useSocketStore } from "../../../../store/store";
const Templates = () => {
- const { templates, removeTemplate } = useTemplateStore();
- const { setTemplates } = useTemplateStore();
+ const { templates, removeTemplate, setTemplates } = useTemplateStore();
const { setSelectedZone, selectedZone } = useSelectedZoneStore();
const { visualizationSocket } = useSocketStore();
@@ -35,15 +32,11 @@ const Templates = () => {
let deleteTemplate = {
organization: organization,
templateID: id,
- }
+ };
if (visualizationSocket) {
- visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate)
+ visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate);
}
removeTemplate(id);
- // let response = await deleteTemplateApi(id, organization);
-
- // if (response.message === "Template deleted successfully") {
- // }
} catch (error) {
console.error("Error deleting template:", error);
}
@@ -60,114 +53,54 @@ const Templates = () => {
organization: organization,
zoneId: selectedZone.zoneId,
templateID: template.id,
- }
- console.log('template: ', template);
- console.log('loadingTemplate: ', loadingTemplate);
+ };
if (visualizationSocket) {
- visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate)
+ visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate);
}
- // 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,
+ 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);
});
-
- 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 (
-
+
{templates.map((template) => (
-
+
{template?.snapshot && (
-
- {" "}
- {/* 16:9 aspect ratio */}
+

handleLoadTemplate(template)}
/>
)}
-
+
handleLoadTemplate(template)}
- style={{
- cursor: "pointer",
- fontWeight: "500",
- // ':hover': {
- // textDecoration: 'underline'
- // }
- }}
+ className="template-name"
>
{template.name}
))}
{templates.length === 0 && (
-
+
No saved templates yet. Create one in the visualization view!
)}
@@ -192,4 +118,3 @@ const Templates = () => {
};
export default Templates;
-
diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
index 8c3df32..09c481a 100644
--- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
+++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx
@@ -46,7 +46,7 @@ const WidgetsFloating = () => {
))} */}
{/* Floating 1 */}
{
const { addTemplate } = useTemplateStore();
const { selectedZone } = useSelectedZoneStore();
const { floatingWidget } = useFloatingWidget();
+
const { widgets3D } = use3DWidget();
+ const zones = useDroppedObjectsStore((state) => state.zones);
+
+
// wall options
const { toggleView, setToggleView } = useToggleView();
const { setDeleteTool } = useDeleteTool();
@@ -409,10 +414,9 @@ const Tools: React.FC = () => {
widgets3D,
selectedZone,
templates,
- visualizationSocket
- })
- }
- }
+ visualizationSocket,
+ });
+ }}
>
diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx
index 0890e5c..03fd44f 100644
--- a/app/src/components/ui/componets/DisplayZone.tsx
+++ b/app/src/components/ui/componets/DisplayZone.tsx
@@ -74,6 +74,7 @@ const DisplayZone: React.FC
= ({
const [showLeftArrow, setShowLeftArrow] = useState(false);
const [showRightArrow, setShowRightArrow] = useState(false);
const { floatingWidget, setFloatingWidget } = useFloatingWidget()
+
const{setSelectedChartId}=useWidgetStore()
// Function to calculate overflow state
@@ -178,7 +179,7 @@ const DisplayZone: React.FC = ({
zoneViewPortPosition: response.viewPortposition || {},
});
} catch (error) {
- console.error(error);
+
}
}
diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx
index fbb376f..cfd002d 100644
--- a/app/src/components/ui/componets/DraggableWidget.tsx
+++ b/app/src/components/ui/componets/DraggableWidget.tsx
@@ -18,6 +18,7 @@ import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData
import { useClickOutside } from "./functions/handleWidgetsOuterClick";
import { useSocketStore } from "../../../store/store";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
+import OuterClick from "../../../utils/outerClick";
type Side = "top" | "bottom" | "left" | "right";
@@ -89,6 +90,11 @@ export const DraggableWidget = ({
const isPanelHidden = hiddenPanels.includes(widget.panel);
+ // OuterClick({
+ // contextClassName: ["chart-container", "floating", "sidebar-right-wrapper"],
+ // setMenuVisible: () => setSelectedChartId(null),
+ // });
+
const deleteSelectedChart = async () => {
try {
const email = localStorage.getItem("email") || "";
@@ -251,36 +257,35 @@ export const DraggableWidget = ({
});
// Track canvas dimensions
-
+ // Current: Two identical useEffect hooks for canvas dimensions
+ // Remove the duplicate and keep only one
+ useEffect(() => {
+ const canvas = document.getElementById("real-time-vis-canvas");
+ if (!canvas) return;
-// Current: Two identical useEffect hooks for canvas dimensions
-// Remove the duplicate and keep only one
-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,
+ });
+ };
- const updateCanvasDimensions = () => {
- const rect = canvas.getBoundingClientRect();
- setCanvasDimensions({
- width: rect.width,
- height: rect.height,
- });
- };
+ updateCanvasDimensions();
+ const resizeObserver = new ResizeObserver(updateCanvasDimensions);
+ resizeObserver.observe(canvas);
- updateCanvasDimensions();
- const resizeObserver = new ResizeObserver(updateCanvasDimensions);
- resizeObserver.observe(canvas);
-
- return () => resizeObserver.unobserve(canvas);
-}, []);
+ return () => resizeObserver.unobserve(canvas);
+ }, []);
return (
<>
@@ -296,13 +301,12 @@ useEffect(() => {
onDragOver={handleDragOver}
onDrop={handleDrop}
style={{
- // Apply styles based on panel position
width: ["top", "bottom"].includes(widget.panel)
- ? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width
- : undefined, // Don't set width if it's left or right
+ ? `calc(${canvasDimensions.width}px / 6)`
+ : undefined,
height: ["left", "right"].includes(widget.panel)
- ? `calc(${canvasDimensions.height * 0.25}px - 2px)` // For left/right panels, set height
- : undefined, // Don't set height if it's top or bottom
+ ? `calc(${canvasDimensions.height - 10}px / 4)`
+ : undefined,
}}
ref={chartWidget}
onClick={() => setSelectedChartId(widget)}
@@ -393,4 +397,4 @@ useEffect(() => {
);
};
-// while resize calculate --realTimeViz-container-height pprperly
\ No newline at end of file
+
diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
index 4652ec1..bd707f4 100644
--- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
+++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
@@ -126,12 +126,11 @@ const DroppedObjects: React.FC = () => {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
-
let deleteFloatingWidget = {
floatWidgetID: id,
organization: organization,
- zoneId: zone.zoneId
- }
+ zoneId: zone.zoneId,
+ };
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
@@ -144,9 +143,7 @@ const DroppedObjects: React.FC = () => {
// if (res.message === "FloatingWidget deleted successfully") {
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
// }
- } catch (error) {
-
- }
+ } catch (error) {}
}
const handlePointerDown = (event: React.PointerEvent, index: number) => {
@@ -461,15 +458,14 @@ const DroppedObjects: React.FC = () => {
position: boundedPosition,
},
index: draggingIndex.index,
- zoneId: zone.zoneId
- }
+ zoneId: zone.zoneId,
+ };
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
}
// if (response.message === "Widget updated successfully") {
- console.log('boundedPosition: ', boundedPosition);
updateObjectPosition(zoneName, draggingIndex.index, boundedPosition);
// }
@@ -503,106 +499,130 @@ const DroppedObjects: React.FC = () => {
setOpenKebabId((prevId) => (prevId === id ? null : id));
};
+ const containerHeight = getComputedStyle(
+ document.documentElement
+ ).getPropertyValue("--realTimeViz-container-height");
+ const containerWidth = getComputedStyle(
+ document.documentElement
+ ).getPropertyValue("--realTimeViz-container-width");
+
+ const heightMultiplier = parseFloat(containerHeight) * 0.14;
+
+ const widthMultiplier = parseFloat(containerWidth) * 0.13;
+
+ console.log("zone.objects: ", zone.objects);
return (
- {zone.objects.map((obj, index) => (
-
{
- setSelectedChartId(obj);
- handlePointerDown(event, index);
- }}
- >
- {obj.className === "floating total-card" ? (
- <>
-
- >
- ) : obj.className === "warehouseThroughput floating" ? (
- <>
-
- >
- ) : obj.className === "fleetEfficiency floating" ? (
- <>
-
- >
- ) : null}
+ {zone.objects.map((obj, index) => {
+ const topPosition =
+ typeof obj.position.top === "number"
+ ? `calc(${obj.position.top}px + ${
+ isPlaying && selectedZone.activeSides.includes("top")
+ ? `${heightMultiplier - 55}px`
+ : "0px"
+ })`
+ : "auto";
+
+ const leftPosition =
+ typeof obj.position.left === "number"
+ ? `calc(${obj.position.left}px + ${
+ isPlaying && selectedZone.activeSides.includes("left")
+ ? `${widthMultiplier - 100}px`
+ : "0px"
+ })`
+ : "auto";
+
+ const rightPosition =
+ typeof obj.position.right === "number"
+ ? `calc(${obj.position.right}px + ${
+ isPlaying && selectedZone.activeSides.includes("right")
+ ? `${widthMultiplier - 100}px`
+ : "0px"
+ })`
+ : "auto";
+
+ const bottomPosition =
+ typeof obj.position.bottom === "number"
+ ? `calc(${obj.position.bottom}px + ${
+ isPlaying && selectedZone.activeSides.includes("bottom")
+ ? `${heightMultiplier - 55}px`
+ : "0px"
+ })`
+ : "auto";
+
+ return (
{
- event.stopPropagation();
- handleKebabClick(obj.id, event);
+ key={`${zoneName}-${index}`}
+ className={`${obj.className} ${
+ selectedChartId?.id === obj.id && "activeChart"
+ }`}
+ ref={chartWidget}
+ style={{
+ position: "absolute",
+ top: topPosition,
+ left: leftPosition,
+ right: rightPosition,
+ bottom: bottomPosition,
+ }}
+ onPointerDown={(event) => {
+ setSelectedChartId(obj);
+ handlePointerDown(event, index);
}}
>
-
-
- {openKebabId === obj.id && (
-
-
{
- event.stopPropagation();
- handleDuplicate(zoneName, index); // Call the duplicate handler
- }}
- >
-
-
-
-
Duplicate
-
-
{
- event.stopPropagation();
- handleDelete(zoneName, obj.id); // Call the delete handler
- }}
- >
-
-
-
-
Delete
-
+ {obj.className === "floating total-card" ? (
+
+ ) : obj.className === "warehouseThroughput floating" ? (
+
+ ) : obj.className === "fleetEfficiency floating" ? (
+
+ ) : null}
+
+
{
+ event.stopPropagation();
+ handleKebabClick(obj.id, event);
+ }}
+ >
+
- )}
-
- ))}
+
+ {openKebabId === obj.id && (
+
+
{
+ event.stopPropagation();
+ handleDuplicate(zoneName, index); // Call the duplicate handler
+ }}
+ >
+
+
+
+
Duplicate
+
+
{
+ event.stopPropagation();
+ handleDelete(zoneName, obj.id); // Call the delete handler
+ }}
+ >
+
+
+
+
Delete
+
+
+ )}
+
+ );
+ })}
{/* Render DistanceLines component during drag */}
{isPlaying === false &&
diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx
index d24abcb..fe9836d 100644
--- a/app/src/components/ui/componets/Panel.tsx
+++ b/app/src/components/ui/componets/Panel.tsx
@@ -32,7 +32,6 @@ interface PanelProps {
zoneName: string;
activeSides: Side[];
panelOrder: Side[];
-
lockedPanels: Side[];
zoneId: string;
zoneViewPortTarget: number[];
@@ -41,7 +40,7 @@ interface PanelProps {
}>
>;
hiddenPanels: string[];
- setZonesData: React.Dispatch
>; // Add this line
+ setZonesData: React.Dispatch>;
}
const generateUniqueId = () =>
@@ -59,14 +58,13 @@ const Panel: React.FC = ({
[side in Side]?: { width: number; height: number };
}>({});
const [openKebabId, setOpenKebabId] = useState(null);
-
const { isPlaying } = usePlayButtonStore();
const { visualizationSocket } = useSocketStore();
-
const [canvasDimensions, setCanvasDimensions] = useState({
width: 0,
height: 0,
});
+
// Track canvas dimensions
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas");
@@ -80,42 +78,20 @@ const Panel: React.FC = ({
});
};
- // Initial measurement
updateCanvasDimensions();
-
- // Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
- return () => {
- resizeObserver.unobserve(canvas);
- };
+ return () => resizeObserver.unobserve(canvas);
}, []);
- 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,
- });
- };
-
- // Initial measurement
- updateCanvasDimensions();
-
- // Set up ResizeObserver to track changes
- const resizeObserver = new ResizeObserver(updateCanvasDimensions);
- resizeObserver.observe(canvas);
-
- return () => {
- resizeObserver.unobserve(canvas);
- };
- }, []);
+ // Calculate panel size
+ const panelSize = Math.max(
+ Math.min(canvasDimensions.width * 0.25, canvasDimensions.height * 0.25),
+ 170 // Min 170px
+ );
+ // Define getPanelStyle
const getPanelStyle = useMemo(
() => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side);
@@ -125,123 +101,105 @@ const Panel: React.FC = ({
const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom");
- // Dynamic panel sizes based on canvas width
- const panelSizeWidth = isPlaying ? Math.max(canvasDimensions.width * 0.14, 200) : Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
- const panelSizeHeight = isPlaying ? Math.max(canvasDimensions.width * 0.13, 200) : Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
-
switch (side) {
case "top":
case "bottom":
return {
- // minWidth: "200px", // Minimum width constraint
- width: `calc(100% - ${(leftActive ? panelSizeWidth : 0) +
- (rightActive ? panelSizeWidth : 0)
- }px)`,
- minHeight: "200px", // Minimum height constraint
- height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin
- left: leftActive ? `${panelSizeWidth}px` : "0",
- right: rightActive ? `${panelSizeWidth}px` : "0",
+ minWidth: "170px",
+ width: `calc(100% - ${
+ (leftActive ? panelSize : 0) + (rightActive ? panelSize : 0)
+ }px)`,
+ minHeight: "170px",
+ height: `${panelSize}px`,
+ left: leftActive ? `${panelSize}px` : "0",
+ right: rightActive ? `${panelSize}px` : "0",
[side]: "0",
};
-
case "left":
case "right":
return {
- minWidth: "200px", // Minimum width constraint
- width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin
- // minHeight: "200px", // Minimum height constraint
- height: `calc(100% - ${(topActive ? panelSizeHeight : 0) +
- (bottomActive ? panelSizeHeight : 0)
- }px)`,
- top: topActive ? `${panelSizeHeight}px` : "0",
- bottom: bottomActive ? `${panelSizeHeight}px` : "0",
+ minWidth: "170px",
+ width: `${panelSize}px`,
+ minHeight: "170px",
+ height: `calc(100% - ${
+ (topActive ? panelSize : 0) + (bottomActive ? panelSize : 0)
+ }px)`,
+ top: topActive ? `${panelSize}px` : "0",
+ bottom: bottomActive ? `${panelSize}px` : "0",
[side]: "0",
};
-
default:
return {};
}
},
- [
- selectedZone.panelOrder,
- isPlaying,
- canvasDimensions.width,
- canvasDimensions.height,
- ]
+ [selectedZone.panelOrder, panelSize]
);
+ // Handle drop event
const handleDrop = (e: React.DragEvent, panel: Side) => {
e.preventDefault();
const { draggedAsset } = useWidgetStore.getState();
- if (!draggedAsset) return;
- if (isPanelLocked(panel)) return;
+ if (!draggedAsset || isPanelLocked(panel)) return;
const currentWidgetsCount = getCurrentWidgetCount(panel);
const maxCapacity = calculatePanelCapacity(panel);
- if (currentWidgetsCount >= maxCapacity) return;
- addWidgetToPanel(draggedAsset, panel);
+ if (currentWidgetsCount < maxCapacity) {
+ addWidgetToPanel(draggedAsset, panel);
+ }
};
+ // Check if panel is locked
const isPanelLocked = (panel: Side) =>
selectedZone.lockedPanels.includes(panel);
+ // Get current widget count in a panel
const getCurrentWidgetCount = (panel: Side) =>
selectedZone.widgets.filter((w) => w.panel === panel).length;
+ // Calculate panel capacity
const calculatePanelCapacity = (panel: Side) => {
- const CHART_WIDTH = 170;
- const CHART_HEIGHT = 170;
- const FALLBACK_HORIZONTAL_CAPACITY = 5;
- const FALLBACK_VERTICAL_CAPACITY = 3;
+ const CHART_WIDTH = panelSize;
+ const CHART_HEIGHT = panelSize;
const dimensions = panelDimensions[panel];
if (!dimensions) {
- return panel === "top" || panel === "bottom"
- ? FALLBACK_HORIZONTAL_CAPACITY
- : FALLBACK_VERTICAL_CAPACITY;
+ return panel === "top" || panel === "bottom" ? 5 : 3; // Fallback capacities
}
return panel === "top" || panel === "bottom"
- ? Math.floor(dimensions.width / CHART_WIDTH)
- : Math.floor(dimensions.height / CHART_HEIGHT);
+ ? Math.max(1, Math.floor(dimensions.width / CHART_WIDTH))
+ : Math.max(1, Math.floor(dimensions.height / CHART_HEIGHT));
};
- // while dublicate check this and add
+ // Add widget to panel
const addWidgetToPanel = async (asset: any, panel: Side) => {
const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0];
+
const newWidget = {
...asset,
id: generateUniqueId(),
panel,
};
+
let addWidget = {
organization: organization,
zoneId: selectedZone.zoneId,
widget: newWidget,
};
+
if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", addWidget);
}
+
setSelectedZone((prev) => ({
...prev,
widgets: [...prev.widgets, newWidget],
}));
-
- try {
- // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
- // if (response.message === "Widget created successfully") {
- // setSelectedZone((prev) => ({
- // ...prev,
- // widgets: [...prev.widgets, newWidget],
- // }));
- // }
- } catch (error) {
- console.error("Error adding widget:", error);
- }
};
+ // Observe panel dimensions
useEffect(() => {
const observers: ResizeObserver[] = [];
const currentPanelRefs = panelRefs.current;
@@ -258,6 +216,7 @@ const Panel: React.FC = ({
}));
}
});
+
observer.observe(element);
observers.push(observer);
}
@@ -268,22 +227,15 @@ const Panel: React.FC = ({
};
}, [selectedZone.activeSides]);
+ // Handle widget reordering
const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => {
- if (!selectedZone) return; // Ensure selectedZone is not null
-
setSelectedZone((prev) => {
- if (!prev) return prev; // Ensure prev is not null
-
- // Filter widgets for the specified panel
const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel);
-
- // Reorder widgets within the same panel
const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex);
- // Merge the reordered widgets back into the full list while preserving the order
const updatedWidgets = prev.widgets
- .filter((widget) => widget.panel !== panel) // Keep widgets from other panels
- .concat(reorderedWidgets); // Add the reordered widgets for the specified panel
+ .filter((widget) => widget.panel !== panel)
+ .concat(reorderedWidgets);
return {
...prev,
@@ -292,13 +244,42 @@ const Panel: React.FC = ({
});
};
+ // Calculate capacities and dimensions
+ const topWidth = getPanelStyle("top").width;
+ const bottomWidth = getPanelStyle("bottom").width;
+ const leftHeight = getPanelStyle("left").height;
+ const rightHeight = getPanelStyle("right").height;
+
+ const topCapacity = calculatePanelCapacity("top");
+ const bottomCapacity = calculatePanelCapacity("bottom");
+ const leftCapacity = calculatePanelCapacity("left");
+ const rightCapacity = calculatePanelCapacity("right");
+
return (
<>
+
+
{selectedZone.activeSides.map((side) => (
handleDrop(e, side)}
onDragOver={(e) => e.preventDefault()}
@@ -344,5 +325,3 @@ const Panel: React.FC
= ({
};
export default Panel;
-
-// canvasDimensions.width as percent
diff --git a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx
index 0c36977..7fafb79 100644
--- a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx
+++ b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx
@@ -5,7 +5,7 @@ interface SimpleCardProps {
icon: React.ComponentType>; // React component for SVG icon
value: string;
per: string; // Percentage change
- position?: [number, number]
+ position?: [number, number];
}
const SimpleCard: React.FC = ({
@@ -15,7 +15,6 @@ const SimpleCard: React.FC = ({
per,
position = [0, 0],
}) => {
-
const handleDragStart = (event: React.DragEvent) => {
const rect = event.currentTarget.getBoundingClientRect(); // Get position
const cardData = JSON.stringify({
@@ -23,7 +22,7 @@ const SimpleCard: React.FC = ({
value,
per,
icon: Icon,
-
+
className: event.currentTarget.className,
position: [rect.top, rect.left], // ✅ Store position
});
diff --git a/app/src/modules/visualization/handleSaveTemplate.ts b/app/src/modules/visualization/handleSaveTemplate.ts
index e5f90ab..f192bec 100644
--- a/app/src/modules/visualization/handleSaveTemplate.ts
+++ b/app/src/modules/visualization/handleSaveTemplate.ts
@@ -64,7 +64,8 @@ export const handleSaveTemplate = async ({
floatingWidget,
widgets3D,
};
-
+
+ console.log('newTemplate: ', newTemplate);
// Extract organization from email
const email = localStorage.getItem("email") || "";
const organization = email.includes("@")
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index 465af2c..3b14aac 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -70,6 +70,67 @@
position: relative;
overflow: auto;
+ .template-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ padding: 1rem;
+ min-height: 50vh;
+ max-height: 60vh;
+ }
+
+ .template-item {
+ border: 1px solid #e0e0e0;
+ border-radius: 8px;
+ padding: 1rem;
+ transition: box-shadow 0.3s ease;
+ }
+
+ .template-image-container {
+ position: relative;
+ padding-bottom: 56.25%; // 16:9 aspect ratio
+ }
+
+ .template-image {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+ }
+
+ .template-details {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 0.5rem;
+ }
+
+ .template-name {
+ cursor: pointer;
+ font-weight: 500;
+ }
+
+ .delete-button {
+ padding: 0.25rem 0.5rem;
+ background: #ff4444;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: opacity 0.3s ease;
+ }
+
+ .no-templates {
+ text-align: center;
+ color: #666;
+ padding: 2rem;
+ grid-column: 1 / -1;
+ }
+
+
.widget-left-sideBar {
min-height: 50vh;
max-height: 60vh;
diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss
index cba4ede..0af1201 100644
--- a/app/src/styles/pages/realTimeViz.scss
+++ b/app/src/styles/pages/realTimeViz.scss
@@ -24,9 +24,17 @@
}
.floating {
- width: 100%;
- max-width: 250px;
- min-height: 83px;
+
+
+ width: calc(var(--realTimeViz-container-width) * 0.2);
+ height: calc(var(--realTimeViz-container-width) * 0.05);
+
+ min-width: 250px;
+ max-width: 300px;
+
+ min-height: 83px !important;
+ // max-height: 100px !important;
+
background: var(--background-color);
border: 1.23px solid var(--border-color);
box-shadow: 0px 4.91px 4.91px 0px #0000001c;
@@ -60,9 +68,8 @@
display: flex;
background-color: var(--background-color);
position: absolute;
- bottom: 10px;
+ // bottom: 10px;
left: 50%;
- transform: translate(-50%, 0);
gap: 6px;
border-radius: 8px;
@@ -70,6 +77,7 @@
overflow: auto;
max-width: calc(100% - 500px);
z-index: 3;
+ transform: translate(-50%, -100%);
&::-webkit-scrollbar {
display: none;
@@ -116,8 +124,8 @@
}
.zone-wrapper.bottom {
- bottom: calc(var(--realTimeViz-container-height) * 0.27);
- bottom: 200px;
+ top: var(--bottomWidth);
+ // bottom: 200px;
}
.content-container {
@@ -138,7 +146,7 @@
display: flex;
background-color: rgba(224, 223, 255, 0.5);
position: absolute;
- bottom: 10px;
+ // bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
gap: 6px;
@@ -203,9 +211,9 @@
.chart-container {
width: 100%;
- min-height: 150px;
+
max-height: 100%;
- // border: 1px dashed var(--background-color-gray);
+ border: 1px dashed var(--background-color-gray);
border-radius: 8px;
box-shadow: var(--box-shadow-medium);
padding: 6px 0;
@@ -343,7 +351,7 @@
.chart-container {
width: 100%;
- min-height: 160px;
+ min-height: 150px;
max-height: 100%;
border-radius: 8px;
box-shadow: var(--box-shadow-medium);
@@ -362,7 +370,7 @@
.playingFlase {
.zone-wrapper.bottom {
- bottom: calc(var(--realTimeViz-container-height) * 0.25);
+ top: var(--bottomWidth);
// bottom: 210px;
}
}
@@ -786,4 +794,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/utils/outerClick.ts b/app/src/utils/outerClick.ts
index de8f7ef..280b3f0 100644
--- a/app/src/utils/outerClick.ts
+++ b/app/src/utils/outerClick.ts
@@ -1,7 +1,7 @@
import React from "react";
interface OuterClickProps {
- contextClassName: string;
+ contextClassName: string[]; // Make sure this is an array of strings
setMenuVisible: React.Dispatch>;
}
@@ -11,8 +11,12 @@ export default function OuterClick({
}: OuterClickProps) {
const handleClick = (event: MouseEvent) => {
const targets = event.target as HTMLElement;
- // Check if the click is outside the selectable-dropdown-wrapper
- if (!targets.closest(`.${contextClassName}`)) {
+ // Check if the click is outside of any of the provided class names
+ const isOutside = contextClassName.every(
+ (className) => !targets.closest(`.${className}`)
+ );
+
+ if (isOutside) {
setMenuVisible(false); // Close the menu by updating the state
}
};
@@ -23,7 +27,7 @@ export default function OuterClick({
return () => {
document.removeEventListener("click", handleClick);
};
- }, []);
+ }, [contextClassName]); // Add contextClassName to dependency array to handle any changes
return null; // This component doesn't render anything
}