diff --git a/app/.env b/app/.env index ff2cfb0..daf92f1 100644 --- a/app/.env +++ b/app/.env @@ -7,6 +7,8 @@ REACT_APP_SERVER_SOCKET_API_BASE_URL=185.100.212.76:8000 # Base URL for the server REST API, used for HTTP requests to the backend server. REACT_APP_SERVER_REST_API_BASE_URL=185.100.212.76:5000 +REACT_APP_SERVER_REST_API_LOCAL_BASE_URL=192.168.0.102:5000 + # Base URL for the server marketplace API. # REACT_APP_SERVER_MARKETPLACE_URL=185.100.212.76:50011 REACT_APP_SERVER_MARKETPLACE_URL=192.168.0.111:3501 diff --git a/app/package-lock.json b/app/package-lock.json index 9a7d772..a820896 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -26,6 +26,7 @@ "@types/react-dom": "^18.3.0", "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", + "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", "leva": "^0.10.0", @@ -8499,6 +8500,15 @@ "pnpm": ">=8" } }, + "node_modules/chartjs-plugin-annotation": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-3.1.0.tgz", + "integrity": "sha512-EkAed6/ycXD/7n0ShrlT1T2Hm3acnbFhgkIEJLa0X+M6S16x0zwj1Fv4suv/2bwayCT3jGPdAtI9uLcAMToaQQ==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=4.0.0" + } + }, "node_modules/check-more-types": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", diff --git a/app/package.json b/app/package.json index 541d3a1..66e3b39 100644 --- a/app/package.json +++ b/app/package.json @@ -21,6 +21,7 @@ "@types/react-dom": "^18.3.0", "@use-gesture/react": "^10.3.1", "chart.js": "^4.4.8", + "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", "leva": "^0.10.0", diff --git a/app/src/components/icons/DashboardIcon.tsx b/app/src/components/icons/DashboardIcon.tsx index 83c997b..f1f4d7d 100644 --- a/app/src/components/icons/DashboardIcon.tsx +++ b/app/src/components/icons/DashboardIcon.tsx @@ -1,255 +1,255 @@ -export function NotificationIcon() { - return ( - - - - - ); -} - -export function HomeIcon() { - return ( - - - - ); -} - -export function ProjectsIcon() { - return ( - - - - ); -} - -export function TutorialsIcon() { - return ( - - - - - - - - - - - - - - - - - - - - ); -} - -export function DocumentationIcon() { - return ( - - - - - ); -} - -export function HelpIcon() { - return ( - - - - - - - - - - - ); -} - -export function LogoutIcon() { - return ( - - - - - - ); -} +export function NotificationIcon() { + return ( + + + + + ); +} + +export function HomeIcon() { + return ( + + + + ); +} + +export function ProjectsIcon() { + return ( + + + + ); +} + +export function TutorialsIcon() { + return ( + + + + + + + + + + + + + + + + + + + + ); +} + +export function DocumentationIcon() { + return ( + + + + + ); +} + +export function HelpIcon() { + return ( + + + + + + + + + + + ); +} + +export function LogoutIcon() { + return ( + + + + + + ); +} diff --git a/app/src/components/layout/Dashboard/DashboardCard.tsx b/app/src/components/layout/Dashboard/DashboardCard.tsx index 0e5df0d..d58bfb6 100644 --- a/app/src/components/layout/Dashboard/DashboardCard.tsx +++ b/app/src/components/layout/Dashboard/DashboardCard.tsx @@ -1,25 +1,25 @@ -import React from "react"; -import { KebabIcon } from "../../icons/ExportCommonIcons"; -import img from "../../../assets/image/image.png" - -const DashboardCard:React.FC = () => { - return ( -
-
- -
-
-
-
Untitled
-
24-12-2025
-
-
-
V
- -
-
-
- ); -}; - -export default DashboardCard; +import React from "react"; +import { KebabIcon } from "../../icons/ExportCommonIcons"; +import img from "../../../assets/image/image.png" + +const DashboardCard:React.FC = () => { + return ( +
+
+ +
+
+
+
Untitled
+
24-12-2025
+
+
+
V
+ +
+
+
+ ); +}; + +export default DashboardCard; diff --git a/app/src/components/layout/Dashboard/DashboardHome.tsx b/app/src/components/layout/Dashboard/DashboardHome.tsx index 9d6672c..38e7bad 100644 --- a/app/src/components/layout/Dashboard/DashboardHome.tsx +++ b/app/src/components/layout/Dashboard/DashboardHome.tsx @@ -1,21 +1,21 @@ -import React from "react"; -import DashboardCard from "./DashboardCard"; -import DashboardNavBar from "./DashboardNavBar"; -import MarketPlaceBanner from "./MarketPlaceBanner"; - -const DashboardHome: React.FC = () => { - return ( -
- - -
-
Recents
-
- -
-
-
- ); -}; - -export default DashboardHome; +import React from "react"; +import DashboardCard from "./DashboardCard"; +import DashboardNavBar from "./DashboardNavBar"; +import MarketPlaceBanner from "./MarketPlaceBanner"; + +const DashboardHome: React.FC = () => { + return ( +
+ + +
+
Recents
+
+ +
+
+
+ ); +}; + +export default DashboardHome; diff --git a/app/src/components/layout/Dashboard/DashboardNavBar.tsx b/app/src/components/layout/Dashboard/DashboardNavBar.tsx index add0656..3da1a61 100644 --- a/app/src/components/layout/Dashboard/DashboardNavBar.tsx +++ b/app/src/components/layout/Dashboard/DashboardNavBar.tsx @@ -1,21 +1,21 @@ -import React from "react"; -import { CartIcon } from "../../icons/ExportModuleIcons"; -import Search from "../../ui/inputs/Search"; - -interface DashboardNavBarProps { - page: React.ReactNode; -} - -const DashboardNavBar: React.FC = ({ page }) => { - return ( -
-
{page}
-
- Market Place -
- {}} /> -
- ); -}; - -export default DashboardNavBar; +import React from "react"; +import { CartIcon } from "../../icons/ExportModuleIcons"; +import Search from "../../ui/inputs/Search"; + +interface DashboardNavBarProps { + page: React.ReactNode; +} + +const DashboardNavBar: React.FC = ({ page }) => { + return ( +
+
{page}
+
+ Market Place +
+ {}} /> +
+ ); +}; + +export default DashboardNavBar; diff --git a/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx b/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx index b0d151a..b89bfb2 100644 --- a/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx +++ b/app/src/components/layout/Dashboard/MarketPlaceBanner.tsx @@ -1,44 +1,44 @@ -import React from "react"; -import banner from "../../../assets/image/banner.png"; - -const MarketPlaceBanner = () => { - return ( -
- {/* market place banner */} - -
- NEW -
FALL -
COLLECTION -
-
Unlock Creativity with Premium 3D Assets!
-
- - - - -
-
Explore Now
-
- ); -}; - -export default MarketPlaceBanner; +import React from "react"; +import banner from "../../../assets/image/banner.png"; + +const MarketPlaceBanner = () => { + return ( +
+ {/* market place banner */} + +
+ NEW +
FALL +
COLLECTION +
+
Unlock Creativity with Premium 3D Assets!
+
+ + + + +
+
Explore Now
+
+ ); +}; + +export default MarketPlaceBanner; diff --git a/app/src/components/layout/Dashboard/SidePannel.tsx b/app/src/components/layout/Dashboard/SidePannel.tsx index 00e3e14..d44c72c 100644 --- a/app/src/components/layout/Dashboard/SidePannel.tsx +++ b/app/src/components/layout/Dashboard/SidePannel.tsx @@ -1,69 +1,69 @@ -import React from "react"; -import { - DocumentationIcon, - HelpIcon, - HomeIcon, - LogoutIcon, - NotificationIcon, - ProjectsIcon, - TutorialsIcon, -} from "../../icons/DashboardIcon"; -import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons"; - -const SidePannel: React.FC = () => { - const userName = localStorage.getItem("userName") || "Anonymous"; - return ( -
-
-
-
{userName[0]}
-
{userName}
-
-
- -
-
-
+ New project
-
-
-
- - Home -
-
- - Projects -
-
- - Trash -
-
- - Tutorials -
-
- - Documentation -
-
-
-
- - Settings -
-
- - Log out -
-
- - Help & Feedback -
-
-
-
- ); -}; - -export default SidePannel; +import React from "react"; +import { + DocumentationIcon, + HelpIcon, + HomeIcon, + LogoutIcon, + NotificationIcon, + ProjectsIcon, + TutorialsIcon, +} from "../../icons/DashboardIcon"; +import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons"; + +const SidePannel: React.FC = () => { + const userName = localStorage.getItem("userName") || "Anonymous"; + return ( +
+
+
+
{userName[0]}
+
{userName}
+
+
+ +
+
+
+ New project
+
+
+
+ + Home +
+
+ + Projects +
+
+ + Trash +
+
+ + Tutorials +
+
+ + Documentation +
+
+
+
+ + Settings +
+
+ + Log out +
+
+ + Help & Feedback +
+
+
+
+ ); +}; + +export default SidePannel; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx new file mode 100644 index 0000000..5938da9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.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 FlotingWidgetInput = (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/floatwidget/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(6)].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 FlotingWidgetInput; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index baf1fcd..32a5590 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -58,11 +58,11 @@ // name: string; // fields: string; // } - + // interface InputData { // [key: string]: Measurement; // } - + // const extractMeasurements = (input: InputData): Measurement[] => { // return Object.values(input); // }; @@ -71,7 +71,7 @@ // const measurementsData = extractMeasurements(selections); // setMeasurements(measurementsData); // }, [selections]); - + // return ( // <> @@ -125,20 +125,22 @@ 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 LineGrapInput = (props: Props) => { - const { setMeasurements, updateDuration } = useChartStore(); + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); const [duration, setDuration] = useState('1h') const [dropDowndata, setDropDownData] = useState({}); - const [selections, setSelections] = 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 { @@ -157,13 +159,14 @@ const LineGrapInput = (props: Props) => { }, []); useEffect(() => { - const fetchSavedInputes = async() => { + 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); } @@ -181,17 +184,19 @@ const LineGrapInput = (props: Props) => { useEffect(() => { setMeasurements(selections); updateDuration(duration); - }, [selections, duration]); + updateName(widgetName); + }, [selections, duration, widgetName]); - const sendInputes = async(inputMeasurement: any, inputDuration: any) => { + 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`,{ + 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:{ + widget: { id: selectedChartId.id, panel: selectedChartId.panel, + widgetName: inputName, Data: { measurements: inputMeasurement, duration: inputDuration @@ -210,35 +215,47 @@ const LineGrapInput = (props: Props) => { } } - 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)) { - setSelections(newSelections); - } - // sendInputes(newSelections, duration); // Send data to server - // return newSelections; + 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)) { + 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(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

-
-
-
-
-
-
-
-
- 0% -
-
{obj.per}%
-
Optimal
-
- 100% -
+ ) : 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 ( - User Avatar - ); -}; - -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 ( + User Avatar + ); +}; + +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; + } +}