+
{[...Array(6)].map((_, index) => {
const inputKey = `input${index + 1}`;
return (
diff --git a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx
index 71847c7..2c9b5c6 100644
--- a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx
+++ b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx
@@ -3,6 +3,7 @@ import { useWidgetStore } from "../../../../../store/useWidgetStore";
import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons";
import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown";
import LineGrapInput from "../IotInputCards/LineGrapInput";
+import RenameInput from "../../../../ui/inputs/RenameInput";
// Define the data structure for demonstration purposes
const DATA_STRUCTURE = {
@@ -107,27 +108,36 @@ const Data = () => {
[selectedChartId.id]: currentChartData.map((group) =>
group.id === groupId
? {
- ...group,
- children: group.children.filter(
- (child) => child.id !== childId
- ),
- }
+ ...group,
+ children: group.children.filter(
+ (child) => child.id !== childId
+ ),
+ }
: group
),
};
});
};
+ console.log("selectedChartId", selectedChartId);
return (
- {selectedChartId?.title && (
+ {/* {selectedChartId?.title && (
{selectedChartId?.title}
- )}
+ )} */}
+
+
+ {/*
*/}
+
{/* Render groups dynamically */}
{
- chartDataGroups[selectedChartId?.id] &&
+ chartDataGroups[selectedChartId?.id] &&
+ <>
+
2D Widget Input
+
+ >
}
-
+
{/* Info Box */}
i
diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx
index 14916b0..db8c408 100644
--- a/app/src/components/ui/componets/DraggableWidget.tsx
+++ b/app/src/components/ui/componets/DraggableWidget.tsx
@@ -306,34 +306,20 @@ export const DraggableWidget = ({
)}
{widget.type === "doughnut" && (
)}
{widget.type === "polarArea" && (
)}
diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
index bf19bb9..4e6d3fa 100644
--- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
+++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx
@@ -10,6 +10,10 @@ import { determinePosition } from "./functions/determinePosition";
import { getActiveProperties } from "./functions/getActiveProperties";
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
+import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent";
+import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent";
+import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent";
+import { useWidgetStore } from "../../../store/useWidgetStore";
const DroppedObjects: React.FC = () => {
const zones = useDroppedObjectsStore((state) => state.zones);
@@ -21,6 +25,7 @@ const DroppedObjects: React.FC = () => {
index: number;
} | null>(null);
const [offset, setOffset] = useState<[number, number] | null>(null);
+ const { setSelectedChartId } = useWidgetStore();
const positionRef = useRef<[number, number] | null>(null);
const animationRef = useRef
(null);
const { activeModule } = useModuleStore();
@@ -29,9 +34,13 @@ const DroppedObjects: React.FC = () => {
const zoneEntries = Object.entries(zones);
if (zoneEntries.length === 0) return null; // No zone, nothing to render
const [zoneName, zone] = zoneEntries[0]; // Only render the first zone
+ console.log("zone", zone);
+
+
// Handle pointer down event
function handlePointerDown(event: React.PointerEvent, index: number) {
+
const obj = zone.objects[index];
const container = document.getElementById("real-time-vis-canvas");
if (!container) return;
@@ -194,53 +203,21 @@ const DroppedObjects: React.FC = () => {
// transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out",
}}
onPointerDown={(event) => handlePointerDown(event, index)}
+ onClick={() => {
+ setSelectedChartId(obj)
+ }}
>
{obj.className === "floating total-card" ? (
<>
-
-
{obj.header}
-
-
{obj.value}
-
{obj.per}
-
-
-
-
-
+
>
) : obj.className === "warehouseThroughput floating" ? (
<>
-
-
Warehouse Throughput
-
- (+5) more in 2025
-
-
-
- {/* */}
-
+
>
) : obj.className === "fleetEfficiency floating" ? (
<>
- Fleet Efficiency
-
-
+
>
) : null}
diff --git a/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx
index 26f7a4b..4876fe4 100644
--- a/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx
+++ b/app/src/components/ui/realTimeVis/charts/BarGraphComponent.tsx
@@ -211,9 +211,10 @@ const BarGraphComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
- const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
+ const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState
({});
const [duration, setDuration] = useState("1h")
+ const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -236,6 +237,10 @@ const BarGraphComponent = ({
],
};
+ useEffect(() => {
+ console.log("titleeeeeeeeeeeeeeeeeee",title);
+ },[])
+
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -270,7 +275,7 @@ const BarGraphComponent = ({
plugins: {
title: {
display: true,
- text: title,
+ text: name,
font: chartFontStyle,
},
legend: {
@@ -285,7 +290,7 @@ const BarGraphComponent = ({
},
},
}),
- [title, chartFontStyle]
+ [title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -304,15 +309,12 @@ const BarGraphComponent = ({
const startStream = () => {
- console.log("inputtttttttttt",inputData);
socket.emit("lineInput", inputData);
};
socket.on("connect", startStream);
socket.on("lineOutput", (response) => {
- console.log("responce dataaaaaaaaa",response.data);
-
const responseData = response.data;
// Extract timestamps and values
@@ -347,6 +349,7 @@ const BarGraphComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
+ setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -365,7 +368,7 @@ const BarGraphComponent = ({
fetchSavedInputes();
}
}
- ,[chartMeasurements, chartDuration])
+ ,[chartMeasurements, chartDuration, widgetName])
return 0 ? chartData : defaultData} options={options} />;
};
diff --git a/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx
index c1d5ac2..6eec49e 100644
--- a/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx
+++ b/app/src/components/ui/realTimeVis/charts/DoughnutGraphComponent.tsx
@@ -1,22 +1,64 @@
-import { useMemo } from "react";
-import { Doughnut, Line } from "react-chartjs-2";
+import React, { useEffect, useMemo, useState } from "react";
+import { Doughnut } from "react-chartjs-2";
+import io from "socket.io-client";
+import { useThemeStore } from "../../../../store/useThemeStore";
+import useChartStore from "../../../../store/useChartStore";
+import { useWidgetStore } from "../../../../store/useWidgetStore";
+import axios from "axios";
interface ChartComponentProps {
+ id: string;
type: any;
title: string;
fontFamily?: string;
fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold";
- data: any;
}
const DoughnutGraphComponent = ({
+ id,
+ type,
title,
fontFamily,
fontSize,
fontWeight = "Regular",
}: ChartComponentProps) => {
- // Memoize Font Weight Mapping
+ const { themeColor } = useThemeStore();
+ const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
+ const [measurements, setmeasurements] = useState({});
+ const [duration, setDuration] = useState("1h")
+ const [name, setName] = useState("Widget")
+ const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
+ labels: [],
+ datasets: [],
+ });
+ const { selectedChartId } = useWidgetStore();
+
+ const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
+ const email = localStorage.getItem("email") || "";
+ const organization = email?.split("@")[1]?.split(".")[0]
+ const defaultData = {
+ labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
+ datasets: [
+ {
+ label: "Dataset",
+ data: [12, 19, 3, 5, 2, 3],
+ backgroundColor: ["#6f42c1"],
+ borderColor: "#b392f0",
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ useEffect(() => {
+ console.log("titleeeeeeeeeeeeeeeeeee",title);
+ },[])
+
+ // Memoize Theme Colors
+ const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
+ const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
+
+ // Memoize Font Styling
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
@@ -26,19 +68,9 @@ const DoughnutGraphComponent = ({
[]
);
- // Parse and Memoize Font Size
- const fontSizeValue = useMemo(
- () => (fontSize ? parseInt(fontSize) : 12),
- [fontSize]
- );
+ const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
+ const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
- // Determine and Memoize Font Weight
- const fontWeightValue = useMemo(
- () => chartFontWeightMap[fontWeight],
- [fontWeight, chartFontWeightMap]
- );
-
- // Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
@@ -48,46 +80,110 @@ const DoughnutGraphComponent = ({
[fontFamily, fontSizeValue, fontWeightValue]
);
- const options = useMemo(
- () => ({
- responsive: true,
- maintainAspectRatio: false,
- plugins: {
- title: {
- display: true,
- text: title,
- font: chartFontStyle,
- },
- legend: {
- display: false,
- },
- },
- scales: {
- x: {
- ticks: {
- display: false, // This hides the x-axis labels
+ // Memoize Chart Options
+ const options = useMemo(
+ () => ({
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ title: {
+ display: true,
+ text: name,
+ font: chartFontStyle,
+ },
+ legend: {
+ display: false,
},
},
- },
- }),
- [title, chartFontStyle]
- );
+ scales: {
+ // x: {
+ // ticks: {
+ // display: true, // This hides the x-axis labels
+ // },
+ // },
+ },
+ }),
+ [title, chartFontStyle, name]
+ );
- const chartData = {
- labels: ["January", "February", "March", "April", "May", "June", "July"],
- datasets: [
- {
- label: "My First Dataset",
- data: [65, 59, 80, 81, 56, 55, 40],
- backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
- borderColor: "#ffffff", // Keeping border color white
- borderWidth: 2,
- fill: false,
- },
- ],
- };
+ // useEffect(() => {console.log(measurements);
+ // },[measurements])
- return ;
+ useEffect(() => {
+ if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
+
+ const socket = io(`http://${iotApiUrl}`);
+
+ const inputData = {
+ measurements,
+ duration,
+ interval: 1000,
+ };
+
+
+ const startStream = () => {
+ socket.emit("lineInput", inputData);
+ };
+
+ socket.on("connect", startStream);
+
+ socket.on("lineOutput", (response) => {
+ const responseData = response.data;
+
+ // Extract timestamps and values
+ const labels = responseData.time;
+ const datasets = Object.keys(measurements).map((key) => {
+ const measurement = measurements[key];
+ const datasetKey = `${measurement.name}.${measurement.fields}`;
+ return {
+ label: datasetKey,
+ data: responseData[datasetKey]?.values ?? [],
+ backgroundColor: "#6f42c1",
+ borderColor: "#b392f0",
+ borderWidth: 1,
+ };
+ });
+
+ setChartData({ labels, datasets });
+ });
+
+ return () => {
+ socket.off("lineOutput");
+ socket.emit("stop_stream"); // Stop streaming when component unmounts
+ socket.disconnect();
+ };
+ }, [measurements, duration, iotApiUrl]);
+
+ const fetchSavedInputes = async() => {
+
+ if (id !== "") {
+ try {
+ const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
+ if (response.status === 200) {
+ setmeasurements(response.data.Data.measurements)
+ setDuration(response.data.Data.duration)
+ setName(response.data.widgetName)
+ } else {
+ console.log("Unexpected response:", response);
+ }
+ } catch (error) {
+ console.error("There was an error!", error);
+ }
+ }
+ }
+
+ useEffect(() => {
+ fetchSavedInputes();
+ }, []);
+
+ useEffect(() => {
+ if (selectedChartId?.id === id) {
+ fetchSavedInputes();
+ }
+ }
+ ,[chartMeasurements, chartDuration, widgetName])
+
+ return 0 ? chartData : defaultData} options={options} />;
};
-export default DoughnutGraphComponent;
+export default DoughnutGraphComponent;
\ No newline at end of file
diff --git a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx
index 34420fa..bf76add 100644
--- a/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx
+++ b/app/src/components/ui/realTimeVis/charts/LineGraphComponent.tsx
@@ -24,9 +24,10 @@ const LineGraphComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
- const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
+ const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState({});
const [duration, setDuration] = useState("1h")
+ const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -49,6 +50,10 @@ const LineGraphComponent = ({
],
};
+ useEffect(() => {
+ console.log("titleeeeeeeeeeeeeeeeeee",title);
+ },[])
+
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -83,7 +88,7 @@ const LineGraphComponent = ({
plugins: {
title: {
display: true,
- text: title,
+ text: name,
font: chartFontStyle,
},
legend: {
@@ -98,7 +103,7 @@ const LineGraphComponent = ({
},
},
}),
- [title, chartFontStyle]
+ [title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -157,6 +162,7 @@ const LineGraphComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
+ setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -175,7 +181,7 @@ const LineGraphComponent = ({
fetchSavedInputes();
}
}
- ,[chartMeasurements, chartDuration])
+ ,[chartMeasurements, chartDuration, widgetName])
return 0 ? chartData : defaultData} options={options} />;
};
diff --git a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx
index 46516fa..094b9e7 100644
--- a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx
+++ b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx
@@ -210,9 +210,10 @@ const PieChartComponent = ({
fontWeight = "Regular",
}: ChartComponentProps) => {
const { themeColor } = useThemeStore();
- const { measurements: chartMeasurements, duration: chartDuration } = useChartStore();
+ const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
const [measurements, setmeasurements] = useState({});
const [duration, setDuration] = useState("1h")
+ const [name, setName] = useState("Widget")
const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
labels: [],
datasets: [],
@@ -235,6 +236,10 @@ const PieChartComponent = ({
],
};
+ useEffect(() => {
+ console.log("titleeeeeeeeeeeeeeeeeee",title);
+ },[])
+
// Memoize Theme Colors
const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
@@ -269,7 +274,7 @@ const PieChartComponent = ({
plugins: {
title: {
display: true,
- text: title,
+ text: name,
font: chartFontStyle,
},
legend: {
@@ -284,7 +289,7 @@ const PieChartComponent = ({
// },
},
}),
- [title, chartFontStyle]
+ [title, chartFontStyle, name]
);
// useEffect(() => {console.log(measurements);
@@ -343,6 +348,7 @@ const PieChartComponent = ({
if (response.status === 200) {
setmeasurements(response.data.Data.measurements)
setDuration(response.data.Data.duration)
+ setName(response.data.widgetName)
} else {
console.log("Unexpected response:", response);
}
@@ -361,7 +367,7 @@ const PieChartComponent = ({
fetchSavedInputes();
}
}
- ,[chartMeasurements, chartDuration])
+ ,[chartMeasurements, chartDuration, widgetName])
return 0 ? chartData : defaultData} options={options} />;
};
diff --git a/app/src/components/ui/realTimeVis/charts/PolarAreaGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/PolarAreaGraphComponent.tsx
index 563e1e9..92581c0 100644
--- a/app/src/components/ui/realTimeVis/charts/PolarAreaGraphComponent.tsx
+++ b/app/src/components/ui/realTimeVis/charts/PolarAreaGraphComponent.tsx
@@ -1,22 +1,64 @@
-import { useMemo } from "react";
-import { Line, PolarArea } from "react-chartjs-2";
+import React, { useEffect, useMemo, useState } from "react";
+import { PolarArea } from "react-chartjs-2";
+import io from "socket.io-client";
+import { useThemeStore } from "../../../../store/useThemeStore";
+import useChartStore from "../../../../store/useChartStore";
+import { useWidgetStore } from "../../../../store/useWidgetStore";
+import axios from "axios";
interface ChartComponentProps {
+ id: string;
type: any;
title: string;
fontFamily?: string;
fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold";
- data: any;
}
const PolarAreaGraphComponent = ({
+ id,
+ type,
title,
fontFamily,
fontSize,
fontWeight = "Regular",
}: ChartComponentProps) => {
- // Memoize Font Weight Mapping
+ const { themeColor } = useThemeStore();
+ const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore();
+ const [measurements, setmeasurements] = useState({});
+ const [duration, setDuration] = useState("1h")
+ const [name, setName] = useState("Widget")
+ const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({
+ labels: [],
+ datasets: [],
+ });
+ const { selectedChartId } = useWidgetStore();
+
+ const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
+ const email = localStorage.getItem("email") || "";
+ const organization = email?.split("@")[1]?.split(".")[0]
+ const defaultData = {
+ labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
+ datasets: [
+ {
+ label: "Dataset",
+ data: [12, 19, 3, 5, 2, 3],
+ backgroundColor: ["#6f42c1"],
+ borderColor: "#b392f0",
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ useEffect(() => {
+ console.log("titleeeeeeeeeeeeeeeeeee",title);
+ },[])
+
+ // Memoize Theme Colors
+ const buttonActionColor = useMemo(() => themeColor[0] || "#5c87df", [themeColor]);
+ const buttonAbortColor = useMemo(() => themeColor[1] || "#ffffff", [themeColor]);
+
+ // Memoize Font Styling
const chartFontWeightMap = useMemo(
() => ({
Light: "lighter" as const,
@@ -26,19 +68,9 @@ const PolarAreaGraphComponent = ({
[]
);
- // Parse and Memoize Font Size
- const fontSizeValue = useMemo(
- () => (fontSize ? parseInt(fontSize) : 12),
- [fontSize]
- );
+ const fontSizeValue = useMemo(() => (fontSize ? parseInt(fontSize) : 12), [fontSize]);
+ const fontWeightValue = useMemo(() => chartFontWeightMap[fontWeight], [fontWeight, chartFontWeightMap]);
- // Determine and Memoize Font Weight
- const fontWeightValue = useMemo(
- () => chartFontWeightMap[fontWeight],
- [fontWeight, chartFontWeightMap]
- );
-
- // Memoize Chart Font Style
const chartFontStyle = useMemo(
() => ({
family: fontFamily || "Arial",
@@ -48,46 +80,110 @@ const PolarAreaGraphComponent = ({
[fontFamily, fontSizeValue, fontWeightValue]
);
- const options = useMemo(
- () => ({
- responsive: true,
- maintainAspectRatio: false,
- plugins: {
- title: {
- display: true,
- text: title,
- font: chartFontStyle,
- },
- legend: {
- display: false,
- },
- },
- scales: {
- x: {
- ticks: {
- display: false, // This hides the x-axis labels
+ // Memoize Chart Options
+ const options = useMemo(
+ () => ({
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ title: {
+ display: true,
+ text: name,
+ font: chartFontStyle,
+ },
+ legend: {
+ display: false,
},
},
- },
- }),
- [title, chartFontStyle]
- );
+ scales: {
+ // x: {
+ // ticks: {
+ // display: true, // This hides the x-axis labels
+ // },
+ // },
+ },
+ }),
+ [title, chartFontStyle, name]
+ );
- const chartData = {
- labels: ["January", "February", "March", "April", "May", "June", "July"],
- datasets: [
- {
- label: "My First Dataset",
- data: [65, 59, 80, 81, 56, 55, 40],
- backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
- borderColor: "#ffffff", // Keeping border color white
- borderWidth: 2,
- fill: false,
- },
- ],
- };
+ // useEffect(() => {console.log(measurements);
+ // },[measurements])
- return ;
+ useEffect(() => {
+ if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
+
+ const socket = io(`http://${iotApiUrl}`);
+
+ const inputData = {
+ measurements,
+ duration,
+ interval: 1000,
+ };
+
+
+ const startStream = () => {
+ socket.emit("lineInput", inputData);
+ };
+
+ socket.on("connect", startStream);
+
+ socket.on("lineOutput", (response) => {
+ const responseData = response.data;
+
+ // Extract timestamps and values
+ const labels = responseData.time;
+ const datasets = Object.keys(measurements).map((key) => {
+ const measurement = measurements[key];
+ const datasetKey = `${measurement.name}.${measurement.fields}`;
+ return {
+ label: datasetKey,
+ data: responseData[datasetKey]?.values ?? [],
+ backgroundColor: "#6f42c1",
+ borderColor: "#b392f0",
+ borderWidth: 1,
+ };
+ });
+
+ setChartData({ labels, datasets });
+ });
+
+ return () => {
+ socket.off("lineOutput");
+ socket.emit("stop_stream"); // Stop streaming when component unmounts
+ socket.disconnect();
+ };
+ }, [measurements, duration, iotApiUrl]);
+
+ const fetchSavedInputes = async() => {
+
+ if (id !== "") {
+ try {
+ const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
+ if (response.status === 200) {
+ setmeasurements(response.data.Data.measurements)
+ setDuration(response.data.Data.duration)
+ setName(response.data.widgetName)
+ } else {
+ console.log("Unexpected response:", response);
+ }
+ } catch (error) {
+ console.error("There was an error!", error);
+ }
+ }
+ }
+
+ useEffect(() => {
+ fetchSavedInputes();
+ }, []);
+
+ useEffect(() => {
+ if (selectedChartId?.id === id) {
+ fetchSavedInputes();
+ }
+ }
+ ,[chartMeasurements, chartDuration, widgetName])
+
+ return 0 ? chartData : defaultData} options={options} />;
};
-export default PolarAreaGraphComponent;
+export default PolarAreaGraphComponent;
\ No newline at end of file
diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx
new file mode 100644
index 0000000..9b2fd7f
--- /dev/null
+++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx
@@ -0,0 +1,33 @@
+import React from 'react'
+
+type Props = {}
+
+const FleetEfficiencyComponent = ({
+ object
+}: any) => {
+ return (
+ <>
+ Fleet Efficiency
+
+
+
0%
+
+
{object.per}%
+
Optimal
+
+
100%
+
+ >
+ )
+}
+
+export default FleetEfficiencyComponent
\ No newline at end of file
diff --git a/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx
new file mode 100644
index 0000000..00ec479
--- /dev/null
+++ b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx
@@ -0,0 +1,29 @@
+import React from 'react'
+import { WalletIcon } from '../../../icons/3dChartIcons'
+import { useWidgetStore } from '../../../../store/useWidgetStore';
+
+const TotalCardComponent = ({
+ object
+}: any) => {
+
+ const { setSelectedChartId } =
+ useWidgetStore();
+ return (
+ <>
+ {
+ setSelectedChartId(object.id)
+ }}>
+
{object.header}
+
+
{object.value}
+
{object.per}
+
+
+
+
+
+ >
+ )
+}
+
+export default TotalCardComponent
\ No newline at end of file
diff --git a/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx
new file mode 100644
index 0000000..3aa8698
--- /dev/null
+++ b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx
@@ -0,0 +1,132 @@
+import React, { useState } from 'react'
+import { Line } from 'react-chartjs-2'
+import axios from 'axios';
+
+const WarehouseThroughputComponent = ({
+ object
+}: any) => {
+
+ const [measurements, setmeasurements] = useState({});
+ const [duration, setDuration] = useState("1h")
+
+ const lineGraphData = {
+ labels: [
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+ ], // Months of the year
+ datasets: [
+ {
+ label: "Throughput (units/month)",
+ data: [500, 400, 300, 450, 350, 250, 200, 300, 250, 150, 100, 150], // Example monthly data
+ borderColor: "#6f42c1", // Use the desired color for the line (purple)
+ backgroundColor: "rgba(111, 66, 193, 0.2)", // Use a semi-transparent purple for the fill
+ borderWidth: 2, // Line thickness
+ fill: true, // Enable fill for this dataset
+ pointRadius: 0, // Remove dots at each data point
+ tension: 0.5, // Smooth interpolation for the line
+ },
+ ],
+ };
+
+ // Line graph options
+ const lineGraphOptions = {
+ responsive: true,
+ maintainAspectRatio: false, // Allow custom height/width adjustments
+ plugins: {
+ legend: {
+ display: false, // Hide legend
+ },
+ title: {
+ display: false, // No chart title needed
+ },
+ tooltip: {
+ callbacks: {
+ label: (context: any) => {
+ const value = context.parsed.y;
+ return `${value} units`; // Customize tooltip to display "units"
+ },
+ },
+ },
+ },
+ scales: {
+ x: {
+ grid: {
+ display: false, // Hide x-axis grid lines
+ },
+ ticks: {
+ maxRotation: 0, // Prevent label rotation
+ autoSkip: false, // Display all months
+ font: {
+ size: 8, // Adjust font size for readability
+ color: "#ffffff", // Light text color for labels
+ },
+ },
+ },
+ y: {
+ display: true, // Show y-axis
+ grid: {
+ drawBorder: false, // Remove border line
+ color: "rgba(255, 255, 255, 0.2)", // Light gray color for grid lines
+ borderDash: [5, 5], // Dotted line style (array defines dash and gap lengths)
+ },
+ ticks: {
+ font: {
+ size: 8, // Adjust font size for readability
+ color: "#ffffff", // Light text color for ticks
+ },
+ },
+ },
+ },
+ elements: {
+ line: {
+ tension: 0.5, // Smooth interpolation for the line
+ },
+ },
+ };
+
+
+ // const fetchSavedInputes = async() => {
+
+ // if (object.id !== "") {
+ // try {
+ // const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`);
+ // if (response.status === 200) {
+ // setmeasurements(response.data.Data.measurements)
+ // setDuration(response.data.Data.duration)
+ // setName(response.data.widgetName)
+ // } else {
+ // console.log("Unexpected response:", response);
+ // }
+ // } catch (error) {
+ // console.error("There was an error!", error);
+ // }
+ // }
+ // }
+
+
+ return (
+ <>
+
+
Warehouse Throughput
+
+ (+5) more in 2025
+
+
+
+
+
+ >
+ )
+}
+
+export default WarehouseThroughputComponent
\ No newline at end of file
diff --git a/app/src/modules/collaboration/users/Avatar.tsx b/app/src/modules/collaboration/users/Avatar.tsx
index 93d45c3..f08a545 100644
--- a/app/src/modules/collaboration/users/Avatar.tsx
+++ b/app/src/modules/collaboration/users/Avatar.tsx
@@ -1,59 +1,59 @@
-import React, { useEffect, useState } from "react";
-import { getInitials } from "./functions/getInitials";
-import { getAvatarColor } from "./functions/getAvatarColor";
-
-interface AvatarProps {
- name: string; // Name can be a full name or initials
- size?: number;
- index?: number;
- textColor?: string;
-}
-
-const CustomAvatar: React.FC = ({
- name,
- size = 100,
- index = 0,
- textColor = "#ffffff",
-}) => {
- const [imageSrc, setImageSrc] = useState(null);
-
- useEffect(() => {
- const canvas = document.createElement("canvas"); // Create an offscreen canvas
- canvas.width = size;
- canvas.height = size;
- const ctx = canvas.getContext("2d");
- if (ctx) {
- const initials = getInitials(name); // Convert name to initials if needed
-
- // Draw background
- ctx.fillStyle = getAvatarColor(index);
- ctx.fillRect(0, 0, size, size);
-
- // Draw initials
- ctx.fillStyle = textColor;
- ctx.font = `bold ${size / 2}px Arial`;
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(initials, size / 2, size / 2);
-
- // Generate image source
- const dataURL = canvas.toDataURL("image/png");
- setImageSrc(dataURL);
- }
- }, [name, size, textColor]);
-
- if (!imageSrc) {
- return null; // Return null while the image is being generated
- }
-
- return (
-
- );
-};
-
-export default CustomAvatar;
+import React, { useEffect, useState } from "react";
+import { getInitials } from "./functions/getInitials";
+import { getAvatarColor } from "./functions/getAvatarColor";
+
+interface AvatarProps {
+ name: string; // Name can be a full name or initials
+ size?: number;
+ index?: number;
+ textColor?: string;
+}
+
+const CustomAvatar: React.FC = ({
+ name,
+ size = 100,
+ index = 0,
+ textColor = "#ffffff",
+}) => {
+ const [imageSrc, setImageSrc] = useState(null);
+
+ useEffect(() => {
+ const canvas = document.createElement("canvas"); // Create an offscreen canvas
+ canvas.width = size;
+ canvas.height = size;
+ const ctx = canvas.getContext("2d");
+ if (ctx) {
+ const initials = getInitials(name); // Convert name to initials if needed
+
+ // Draw background
+ ctx.fillStyle = getAvatarColor(index);
+ ctx.fillRect(0, 0, size, size);
+
+ // Draw initials
+ ctx.fillStyle = textColor;
+ ctx.font = `bold ${size / 2}px Arial`;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText(initials, size / 2, size / 2);
+
+ // Generate image source
+ const dataURL = canvas.toDataURL("image/png");
+ setImageSrc(dataURL);
+ }
+ }, [name, size, textColor]);
+
+ if (!imageSrc) {
+ return null; // Return null while the image is being generated
+ }
+
+ return (
+
+ );
+};
+
+export default CustomAvatar;
diff --git a/app/src/modules/collaboration/users/functions/getAvatarColor.ts b/app/src/modules/collaboration/users/functions/getAvatarColor.ts
index d3186d2..3deacca 100644
--- a/app/src/modules/collaboration/users/functions/getAvatarColor.ts
+++ b/app/src/modules/collaboration/users/functions/getAvatarColor.ts
@@ -1,26 +1,26 @@
-const avatarColors: string[] = [
- "#FF5733", // Red Orange
- "#48ac2a", // Leaf Green
- "#0050eb", // Royal Blue
- "#FF33A1", // Hot Pink
- "#FF8C33", // Deep Orange
- "#8C33FF", // Violet
- "#FF3333", // Bright Red
- "#43c06d", // Emerald Green
- "#A133FF", // Amethyst Purple
- "#C70039", // Crimson
- "#900C3F", // Maroon
- "#581845", // Plum
- "#3498DB", // Sky Blue
- "#2ECC71", // Green Mint
- "#E74C3C", // Tomato Red
- "#00adff", // Azure
- "#DBAD05", // Amber Yellow
- "#FF5733", // Red Orange
- "#FF33A1", // Hot Pink
- "#900C3F", // Maroon
-];
-
-export function getAvatarColor(index: number): string {
- return avatarColors[index % avatarColors.length];
-}
+const avatarColors: string[] = [
+ "#FF5733", // Red Orange
+ "#48ac2a", // Leaf Green
+ "#0050eb", // Royal Blue
+ "#FF33A1", // Hot Pink
+ "#FF8C33", // Deep Orange
+ "#8C33FF", // Violet
+ "#FF3333", // Bright Red
+ "#43c06d", // Emerald Green
+ "#A133FF", // Amethyst Purple
+ "#C70039", // Crimson
+ "#900C3F", // Maroon
+ "#581845", // Plum
+ "#3498DB", // Sky Blue
+ "#2ECC71", // Green Mint
+ "#E74C3C", // Tomato Red
+ "#00adff", // Azure
+ "#DBAD05", // Amber Yellow
+ "#FF5733", // Red Orange
+ "#FF33A1", // Hot Pink
+ "#900C3F", // Maroon
+];
+
+export function getAvatarColor(index: number): string {
+ return avatarColors[index % avatarColors.length];
+}
diff --git a/app/src/modules/collaboration/users/functions/getInitials.ts b/app/src/modules/collaboration/users/functions/getInitials.ts
index 5ebaa19..572d49a 100644
--- a/app/src/modules/collaboration/users/functions/getInitials.ts
+++ b/app/src/modules/collaboration/users/functions/getInitials.ts
@@ -1,10 +1,10 @@
-export const getInitials = (fullName: string): string => {
- // Extract initials from the name
- const words = fullName.split(" ");
- const initials = words
- .map((word) => word[0])
- .slice(0, 2)
- .join("")
- .toUpperCase();
- return initials;
+export const getInitials = (fullName: string): string => {
+ // Extract initials from the name
+ const words = fullName.split(" ");
+ const initials = words
+ .map((word) => word[0])
+ .slice(0, 2)
+ .join("")
+ .toUpperCase();
+ return initials;
};
\ No newline at end of file
diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts
index 26a88c5..71d9c2f 100644
--- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts
+++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts
@@ -1,4 +1,5 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
+console.log("url_Backend_dwinzo: ", url_Backend_dwinzo);
export const getSelect2dZoneData = async (
ZoneId?: string,
diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts
index a760959..100b6ff 100644
--- a/app/src/services/realTimeVisulization/zoneData/getZones.ts
+++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts
@@ -14,7 +14,6 @@ export const getZoneData = async (zoneId: string, organization: string) => {
}
);
-
if (!response.ok) {
throw new Error("Failed to fetch zoneData");
}
diff --git a/app/src/store/useChartStore.ts b/app/src/store/useChartStore.ts
index 4d61952..079b9ff 100644
--- a/app/src/store/useChartStore.ts
+++ b/app/src/store/useChartStore.ts
@@ -9,20 +9,26 @@ interface MeasurementStore {
measurements: Record; // Change array to Record
interval: number;
duration: string;
+ name: string;
setMeasurements: (newMeasurements: Record) => void;
updateDuration: (newDuration: string) => void;
+ updateName: (newName: string) => void;
}
const useChartStore = create((set) => ({
measurements: {}, // Initialize as an empty object
interval: 1000,
duration: "1h",
+ name:'',
setMeasurements: (newMeasurements) =>
set(() => ({ measurements: newMeasurements })),
updateDuration: (newDuration) =>
set(() => ({ duration: newDuration })),
+
+ updateName: (newName) =>
+ set(() => ({ duration: newName })),
}));
export default useChartStore;
diff --git a/app/src/store/useWidgetStore.ts b/app/src/store/useWidgetStore.ts
index 115c6aa..047b57b 100644
--- a/app/src/store/useWidgetStore.ts
+++ b/app/src/store/useWidgetStore.ts
@@ -33,7 +33,7 @@ interface WidgetStore {
setDraggedAsset: (asset: Widget | null) => void; // Setter for draggedAsset
addWidget: (widget: Widget) => void; // Add a new widget
setWidgets: (widgets: Widget[]) => void; // Replace the entire widgets array
- setSelectedChartId: (widget: Widget | null) => void; // Set the selected chart/widget
+ setSelectedChartId: (widget: any | null) => void; // Set the selected chart/widget
}
// Create the store with Zustand
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index 79971f2..f5e1b27 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -318,6 +318,25 @@
.sidebar-right-content-container {
.dataSideBar {
+ .inputs-wrapper {
+ .datas {
+
+ .input-value {
+
+ padding: 5px 10px;
+ }
+
+ .input-value,
+ .rename-input {
+ margin-right: 24px;
+ width: 170px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+ }
+
width: 100%;
height: 100%;
display: flex;
@@ -991,11 +1010,9 @@
top: 50%;
right: -10px;
transform: translate(0, -50%);
- background: linear-gradient(
- 144.19deg,
- #f1e7cd 16.62%,
- #fffaef 85.81%
- );
+ background: linear-gradient(144.19deg,
+ #f1e7cd 16.62%,
+ #fffaef 85.81%);
}
.category-image {
@@ -1058,4 +1075,4 @@
cursor: pointer;
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/styles/pages/dashboard.scss b/app/src/styles/pages/dashboard.scss
index e5b07a4..3fc9a05 100644
--- a/app/src/styles/pages/dashboard.scss
+++ b/app/src/styles/pages/dashboard.scss
@@ -1,221 +1,221 @@
-@use "../abstracts/variables.scss" as *;
-@use "../abstracts/mixins.scss" as *;
-
-.dashboard-main {
- height: 100vh;
- width: 100vw;
- display: flex;
- .side-pannel-container {
- padding: 32px;
- min-width: 240px;
- height: 100vh;
- display: flex;
- flex-direction: column;
- gap: 16px;
- border-right: 1px solid var(--border-color);
- .side-pannel-header {
- @include flex-space-between;
- .user-container {
- @include flex-center;
- gap: 6px;
- .user-profile {
- height: 32px;
- width: 32px;
- line-height: 32px;
- text-align: center;
- font-weight: var(--font-weight-medium);
- background: var(--accent-color);
- color: var(--primary-color);
- border-radius: #{$border-radius-circle};
- }
- .user-name {
- color: var(--accent-color);
- }
- }
- .notifications-container {
- @include flex-center;
- height: 24px;
- width: 24px;
- cursor: pointer;
- }
- }
- .new-project-button {
- padding: 12px 16px;
- cursor: not-allowed;
- color: var(--accent-color);
- background-color: var(--background-color-secondary);
- border-radius: #{$border-radius-large};
- }
- .side-bar-content-container {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- height: 100%;
- .side-bar-options-container {
- .option-list {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 6px 10px;
- margin: 4px 0;
- border-radius: #{$border-radius-medium};
- &:hover {
- background: var(--background-color-secondary);
- }
- }
- .active {
- color: var(--accent-color);
- font-weight: var(--font-weight-medium);
- background-color: var(--highlight-accent-color);
- &:hover {
- background-color: var(--highlight-accent-color);
- }
- }
- }
- }
- }
- .dashboard-home-container {
- width: 100%;
- .dashboard-navbar-container {
- margin-top: 28px;
- padding: 8px 34px 8px 12px;
- @include flex-center;
- .title {
- text-transform: capitalize;
- font-size: var(--font-size-large);
- width: 100%;
- }
- .market-place-button {
- @include flex-center;
- gap: 6px;
- padding: 8px 14px;
- background: var(--accent-gradient-color);
- white-space: nowrap;
- border-radius: #{$border-radius-large};
- color: var(--primary-color);
- }
- .search-wrapper {
- width: 400px;
- }
- }
- .container {
- margin: 22px 0;
- width: 100%;
- padding: 0 12px;
- .header {
- font-size: var(--font-size-large);
- }
- .cards-container {
- display: flex;
- flex-wrap: wrap;
- position: relative;
- width: 100%;
- padding: 8px;
- gap: 18px;
- }
- }
- }
-}
-
-.dashboard-card-container {
- height: 242px;
- width: calc((100% / 5) - 23px);
- min-width: 260px;
- position: relative;
- border: 1px solid var(--border-color);
- border-radius: #{$border-radius-large};
- overflow: hidden;
- .preview-container {
- height: 100%;
- width: 100%;
- img {
- height: 100%;
- width: 100%;
- object-fit: cover;
- vertical-align: top;
- border: none;
- outline: none;
- }
- }
- .project-details-container {
- @include flex-space-between;
- position: absolute;
- bottom: 0;
- width: 100%;
- padding: 8px 16px;
- background: var(--primary-color);
- border-radius: 10px;
- .project-details {
- .project-name {
- margin-bottom: 2px;
- }
- .project-data {
- color: var(--accent-color);
- }
- }
- .users-list-container {
- @include flex-center;
- gap: 6px;
- .user-profile {
- height: 26px;
- width: 26px;
- line-height: 26px;
- text-align: center;
- background-color: var(--accent-color);
- color: var(--primary-color);
- border-radius: #{$border-radius-circle};
- }
- }
- }
-}
-
-.market-place-banner-container {
- width: 100%;
- height: 230px;
- overflow: hidden;
- position: relative;
- padding: 0 24px;
- img {
- height: 100%;
- width: 100%;
- object-fit: cover;
- border-radius: 30px;
- }
- .hero-text {
- position: absolute;
- left: 52px;
- bottom: 25px;
- font-size: 48px;
- font-family: #{$font-roboto};
- font-weight: 800;
- color: #ffffff;
- text-transform: uppercase;
- }
- .context {
- position: absolute;
- top: 20px;
- right: 58px;
- text-transform: uppercase;
- font-size: 22px;
- width: 300px;
- color: #ffffff;
- font-family: #{$font-roboto};
- }
- .arrow-context {
- position: absolute;
- bottom: 27px;
- right: 300px;
- }
- .explore-button {
- position: absolute;
- top: 95px;
- right: 52px;
- padding: 10px 20px;
- text-transform: uppercase;
- font-size: 24px;
- border: 1px solid #ffffff;
- color: #ffffff;
- font-family: #{$font-roboto};
- cursor: pointer;
- }
-}
+@use "../abstracts/variables.scss" as *;
+@use "../abstracts/mixins.scss" as *;
+
+.dashboard-main {
+ height: 100vh;
+ width: 100vw;
+ display: flex;
+ .side-pannel-container {
+ padding: 32px;
+ min-width: 240px;
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ border-right: 1px solid var(--border-color);
+ .side-pannel-header {
+ @include flex-space-between;
+ .user-container {
+ @include flex-center;
+ gap: 6px;
+ .user-profile {
+ height: 32px;
+ width: 32px;
+ line-height: 32px;
+ text-align: center;
+ font-weight: var(--font-weight-medium);
+ background: var(--accent-color);
+ color: var(--primary-color);
+ border-radius: #{$border-radius-circle};
+ }
+ .user-name {
+ color: var(--accent-color);
+ }
+ }
+ .notifications-container {
+ @include flex-center;
+ height: 24px;
+ width: 24px;
+ cursor: pointer;
+ }
+ }
+ .new-project-button {
+ padding: 12px 16px;
+ cursor: not-allowed;
+ color: var(--accent-color);
+ background-color: var(--background-color-secondary);
+ border-radius: #{$border-radius-large};
+ }
+ .side-bar-content-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: 100%;
+ .side-bar-options-container {
+ .option-list {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 10px;
+ margin: 4px 0;
+ border-radius: #{$border-radius-medium};
+ &:hover {
+ background: var(--background-color-secondary);
+ }
+ }
+ .active {
+ color: var(--accent-color);
+ font-weight: var(--font-weight-medium);
+ background-color: var(--highlight-accent-color);
+ &:hover {
+ background-color: var(--highlight-accent-color);
+ }
+ }
+ }
+ }
+ }
+ .dashboard-home-container {
+ width: 100%;
+ .dashboard-navbar-container {
+ margin-top: 28px;
+ padding: 8px 34px 8px 12px;
+ @include flex-center;
+ .title {
+ text-transform: capitalize;
+ font-size: var(--font-size-large);
+ width: 100%;
+ }
+ .market-place-button {
+ @include flex-center;
+ gap: 6px;
+ padding: 8px 14px;
+ background: var(--accent-gradient-color);
+ white-space: nowrap;
+ border-radius: #{$border-radius-large};
+ color: var(--primary-color);
+ }
+ .search-wrapper {
+ width: 400px;
+ }
+ }
+ .container {
+ margin: 22px 0;
+ width: 100%;
+ padding: 0 12px;
+ .header {
+ font-size: var(--font-size-large);
+ }
+ .cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ position: relative;
+ width: 100%;
+ padding: 8px;
+ gap: 18px;
+ }
+ }
+ }
+}
+
+.dashboard-card-container {
+ height: 242px;
+ width: calc((100% / 5) - 23px);
+ min-width: 260px;
+ position: relative;
+ border: 1px solid var(--border-color);
+ border-radius: #{$border-radius-large};
+ overflow: hidden;
+ .preview-container {
+ height: 100%;
+ width: 100%;
+ img {
+ height: 100%;
+ width: 100%;
+ object-fit: cover;
+ vertical-align: top;
+ border: none;
+ outline: none;
+ }
+ }
+ .project-details-container {
+ @include flex-space-between;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ padding: 8px 16px;
+ background: var(--primary-color);
+ border-radius: 10px;
+ .project-details {
+ .project-name {
+ margin-bottom: 2px;
+ }
+ .project-data {
+ color: var(--accent-color);
+ }
+ }
+ .users-list-container {
+ @include flex-center;
+ gap: 6px;
+ .user-profile {
+ height: 26px;
+ width: 26px;
+ line-height: 26px;
+ text-align: center;
+ background-color: var(--accent-color);
+ color: var(--primary-color);
+ border-radius: #{$border-radius-circle};
+ }
+ }
+ }
+}
+
+.market-place-banner-container {
+ width: 100%;
+ height: 230px;
+ overflow: hidden;
+ position: relative;
+ padding: 0 24px;
+ img {
+ height: 100%;
+ width: 100%;
+ object-fit: cover;
+ border-radius: 30px;
+ }
+ .hero-text {
+ position: absolute;
+ left: 52px;
+ bottom: 25px;
+ font-size: 48px;
+ font-family: #{$font-roboto};
+ font-weight: 800;
+ color: #ffffff;
+ text-transform: uppercase;
+ }
+ .context {
+ position: absolute;
+ top: 20px;
+ right: 58px;
+ text-transform: uppercase;
+ font-size: 22px;
+ width: 300px;
+ color: #ffffff;
+ font-family: #{$font-roboto};
+ }
+ .arrow-context {
+ position: absolute;
+ bottom: 27px;
+ right: 300px;
+ }
+ .explore-button {
+ position: absolute;
+ top: 95px;
+ right: 52px;
+ padding: 10px 20px;
+ text-transform: uppercase;
+ font-size: 24px;
+ border: 1px solid #ffffff;
+ color: #ffffff;
+ font-family: #{$font-roboto};
+ cursor: pointer;
+ }
+}