From 03e7c32bfbd1e58881870430e7c1626a9c49f0c1 Mon Sep 17 00:00:00 2001 From: gabriel Date: Tue, 1 Apr 2025 14:27:19 +0530 Subject: [PATCH] Merge branch 'realTimeVisulization' of http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev into realTimeVisulization --- .../visualization/widgets/Widgets2D.tsx | 1 + .../IotInputCards/BarChartInput.tsx | 177 +++++++++++++ .../IotInputCards/FlotingWidgetInput.tsx | 19 +- .../IotInputCards/InputSelecterComponent.tsx | 75 ++++++ .../IotInputCards/LineGrapInput.tsx | 2 +- .../IotInputCards/PieChartInput.tsx | 241 ++++++++++++------ .../WarehouseThroughputInputComponent.tsx | 178 +++++++++++++ .../sidebarRight/visualization/data/Data.tsx | 4 +- .../ui/componets/DroppedFloatingWidgets.tsx | 3 +- .../realTimeVis/floating/FleetEfficiency.tsx | 4 +- .../floating/FleetEfficiencyComponent.tsx | 15 +- .../floating/WarehouseThroughputComponent.tsx | 117 +++++++-- app/src/store/store.ts | 2 +- app/src/store/useChartStore.ts | 20 +- app/src/styles/pages/realTimeViz.scss | 2 +- 15 files changed, 741 insertions(+), 119 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx index 4c90582..c3696e0 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx @@ -99,6 +99,7 @@ const ProgressBarWidget = ({ ); }; +console.log(chartTypes,"chartTypes"); const Widgets2D = () => { return ( diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx new file mode 100644 index 0000000..8fe71a6 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx @@ -0,0 +1,177 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const BarChartInput = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + 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] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(3)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default BarChartInput; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx index 5938da9..0a58634 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx @@ -12,7 +12,7 @@ type Props = {}; const FlotingWidgetInput = (props: Props) => { const [widgetName, setWidgetName] = useState('Widget'); - const { setMeasurements, updateDuration, updateName } = useChartStore(); + const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore(); const [duration, setDuration] = useState('1h') const [dropDowndata, setDropDownData] = useState({}); const [selections, setSelections] = useState>({}); @@ -43,11 +43,13 @@ const FlotingWidgetInput = (props: Props) => { const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); if (response.status === 200) { + console.log(response.data); + setSelections(response.data.Data.measurements) setDuration(response.data.Data.duration) - setWidgetName(response.data.widgetName) + setWidgetName(response.data.header) } else { console.log("Unexpected response:", response); } @@ -63,9 +65,9 @@ const FlotingWidgetInput = (props: Props) => { // Sync Zustand state when component mounts useEffect(() => { - setMeasurements(selections); - updateDuration(duration); - updateName(widgetName); + setFlotingMeasurements(selections); + updateFlotingDuration(duration); + updateHeader(widgetName); }, [selections, duration, widgetName]); @@ -76,8 +78,7 @@ const FlotingWidgetInput = (props: Props) => { zoneId: selectedZone.zoneId, widget: { id: selectedChartId.id, - panel: selectedChartId.panel, - widgetName: inputName, + header: inputName, Data: { measurements: inputMeasurement, duration: inputDuration @@ -135,7 +136,7 @@ const FlotingWidgetInput = (props: Props) => {
Title
- +
{[...Array(6)].map((_, index) => { const inputKey = `input${index + 1}`; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx new file mode 100644 index 0000000..45ce802 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx @@ -0,0 +1,75 @@ +import React from 'react' +import LineGrapInput from './LineGrapInput' +import BarChartInput from './BarChartInput' +import PieChartInput from './PieChartInput' +import FlotingWidgetInput from './FlotingWidgetInput' +import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent' +import { useWidgetStore } from '../../../../../store/useWidgetStore' + +const InputSelecterComponent = () => { + const { selectedChartId } = useWidgetStore(); + console.log('selectedChartId:',selectedChartId); + + + if (selectedChartId && selectedChartId.type && selectedChartId.type === 'bar' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'line' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'pie' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'doughnut' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'polarArea' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) { + return ( + <> +
Floting Widget Input
+ + + ) + } + + else { + return ( +
No chart selected
+ ) + } +} + +export default InputSelecterComponent \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index 32a5590..017dc6d 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -256,7 +256,7 @@ const LineGrapInput = (props: Props) => {
Title
- {[...Array(6)].map((_, index) => { + {[...Array(4)].map((_, index) => { const inputKey = `input${index + 1}`; return (
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx index 3087471..e3bed25 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -1,78 +1,177 @@ -import React, { useEffect, useState } from 'react' -import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown' -import { AddIcon } from '../../../../icons/ExportCommonIcons' -import axios from 'axios' +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; -type Props = {} +type Props = {}; const PieChartInput = (props: Props) => { - const [dropDowndata, setDropDownData] = useState({}) - const [selections, setSelections] = useState>({}) - const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + 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] - useEffect(() => { - const fetchZoneData = async () => { - try { - const response = await axios.get(`http://${iotApiUrl}/getinput`); - if (response.status === 200) { - console.log('dropdown data:', response.data); - setDropDownData(response.data) - } else { - console.log('Unexpected response:', response); - } - } catch (error) { - console.error('There was an error!', error); - } - }; - fetchZoneData(); - }, []); - - useEffect(() => {console.log(selections); - },[selections]) - - const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => { - setSelections(prev => { - if (selectedData === null) { - const newSelections = {...prev}; - delete newSelections[inputKey]; - return newSelections; - } else { - return { - ...prev, - [inputKey]: selectedData - }; - } - }); + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } }; + fetchZoneData(); + }, []); - return ( - <> -
- {[...Array(3)].map((_, index) => { - const inputKey = `input${index+1}`; - return ( -
-
Input {index+1}
-
- handleSelect(inputKey, selectedData)} - onUnselect={() => handleSelect(inputKey, null)} - selectedValue={selections[inputKey]} - /> -
- -
-
-
- ); - })} -
-
- -
- - ) -} + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } -export default PieChartInput \ No newline at end of file + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(2)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default PieChartInput; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx new file mode 100644 index 0000000..cd8cb96 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx @@ -0,0 +1,178 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const WarehouseThroughputInputComponent = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + 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] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + console.log(response.data); + + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setFlotingMeasurements(selections); + updateFlotingDuration(duration); + updateHeader(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + header: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(1)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default WarehouseThroughputInputComponent; diff --git a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx index 2c9b5c6..1b9969c 100644 --- a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx +++ b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx @@ -4,6 +4,7 @@ import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown"; import LineGrapInput from "../IotInputCards/LineGrapInput"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import InputSelecterComponent from "../IotInputCards/InputSelecterComponent"; // Define the data structure for demonstration purposes const DATA_STRUCTURE = { @@ -133,8 +134,7 @@ const Data = () => { { chartDataGroups[selectedChartId?.id] && <> -
2D Widget Input
- + } diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index d7a6960..35278bb 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -379,14 +379,13 @@ const DroppedObjects: React.FC = () => { ) : obj.className === "warehouseThroughput floating" ? ( <> - + ) : obj.className === "fleetEfficiency floating" ? ( <> ) : null} - {renderObjectContent(obj)}
handleKebabClick(obj.id, event)} diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx index 07e5f19..cabc3e7 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx @@ -1,8 +1,8 @@ const FleetEfficiency = () => { - const progress = 75; // Example progress value (0-100) + const progress = 50; // Example progress value (0-100) // Calculate the rotation angle for the progress bar - const rotationAngle = -90 + progress * 3.6; // Progress starts from the left (-90°) + const rotationAngle = 45 + progress * 1.8; const handleDragStart = (event: React.DragEvent) => { const rect = event.currentTarget.getBoundingClientRect(); // Get position diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx index 9b2fd7f..e9221e8 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx @@ -1,10 +1,11 @@ -import React from 'react' +import React,{ useEffect, useState} from 'react' -type Props = {} +const FleetEfficiencyComponent = ({object}: any) => { + const [ progress, setProgress ] = useState(0) -const FleetEfficiencyComponent = ({ - object -}: any) => { + // Calculate the rotation angle for the progress bar + const rotationAngle = 45 + progress * 1.8; + return ( <>

Fleet Efficiency

@@ -13,7 +14,7 @@ const FleetEfficiencyComponent = ({
@@ -21,7 +22,7 @@ const FleetEfficiencyComponent = ({
0%
-
{object.per}%
+
{progress}%
Optimal
100% diff --git a/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx index 3aa8698..22f6529 100644 --- a/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx @@ -1,6 +1,9 @@ -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import { Line } from 'react-chartjs-2' +import useChartStore from '../../../../store/useChartStore'; +import { useWidgetStore } from '../../../../store/useWidgetStore'; import axios from 'axios'; +import io from "socket.io-client"; const WarehouseThroughputComponent = ({ object @@ -8,6 +11,17 @@ const WarehouseThroughputComponent = ({ const [measurements, setmeasurements] = useState({}); const [duration, setDuration] = useState("1h") + const [name, setName] = useState(object.header ? object.header : '') + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const lineGraphData = { labels: [ @@ -95,35 +109,94 @@ const WarehouseThroughputComponent = ({ }; - // const fetchSavedInputes = async() => { + 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 ?? [], + 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 + }; + }); + + 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 (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]) - // 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

-

+

{name}

+ {/*

(+5) more in 2025 -

+

*/}
- + 0 ? chartData : lineGraphData} options={lineGraphOptions} />
) diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 6affa99..ef5c25f 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -11,7 +11,7 @@ export const useSocketStore = create((set: any, get: any) => ({ return; } - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { + const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, { reconnection: false, auth: { email, organization }, }); diff --git a/app/src/store/useChartStore.ts b/app/src/store/useChartStore.ts index 079b9ff..cdd8de0 100644 --- a/app/src/store/useChartStore.ts +++ b/app/src/store/useChartStore.ts @@ -10,9 +10,15 @@ interface MeasurementStore { interval: number; duration: string; name: string; + header: string; + flotingDuration: string; + flotingMeasurements: Record; // Change array to Record setMeasurements: (newMeasurements: Record) => void; updateDuration: (newDuration: string) => void; updateName: (newName: string) => void; + updateHeader: (newHeader: string) => void; + updateFlotingDuration: (newFlotingDuration: string) => void; + setFlotingMeasurements: (newFlotingMeasurements: Record) => void; } const useChartStore = create((set) => ({ @@ -20,6 +26,9 @@ const useChartStore = create((set) => ({ interval: 1000, duration: "1h", name:'', + header:'', + flotingDuration: "1h", + flotingMeasurements: {}, setMeasurements: (newMeasurements) => set(() => ({ measurements: newMeasurements })), @@ -28,7 +37,16 @@ const useChartStore = create((set) => ({ set(() => ({ duration: newDuration })), updateName: (newName) => - set(() => ({ duration: newName })), + set(() => ({ name: newName })), + + updateHeader: (newHeader) => + set(() => ({ header: newHeader })), + + updateFlotingDuration: (newFlotingDuration) => + set(() => ({ flotingDuration: newFlotingDuration })), + + setFlotingMeasurements: (newFlotingMeasurements) => + set(() => ({ flotingMeasurements: newFlotingMeasurements })), })); export default useChartStore; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index d58f12d..4440e6d 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -196,7 +196,7 @@ border-radius: 8px; box-shadow: 0px 2px 6px 0px rgba(60, 60, 67, 0.1); padding: 6px 0; - background-color: white; + background-color: var(--background-color); position: relative; .kebab {