diff options
| author | Arne Rief <riearn@proton.me> | 2025-12-20 14:09:20 +0100 |
|---|---|---|
| committer | Arne Rief <riearn@proton.me> | 2025-12-20 14:09:20 +0100 |
| commit | 237f8ae6c29bbf485c312b2fed4d5ab4f99a4eff (patch) | |
| tree | 238e82a6dc22372c2f9bb8504ab9160be49bd4f3 /frontend/src/pages/Dashboard.tsx | |
| parent | 655ec610fcce8dd7748f10772d520bdff4f7c78e (diff) | |
Map and loading robots
Diffstat (limited to 'frontend/src/pages/Dashboard.tsx')
| -rw-r--r-- | frontend/src/pages/Dashboard.tsx | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index f306c53..6b43bf8 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -1,5 +1,92 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { FadeLoader } from "react-spinners"; +import { io } from "socket.io-client"; +import CityMap from "../components/CityMap"; +import Header from "../components/Header"; +import API_URL from "../config"; +import "../styles/dashboard.css"; +import type { ErrorResponse } from "../types/error"; +import type { AuthorizedUser } from "../types/login"; +import type { Robot, RobotsResponse } from "../types/robot"; + function Dashboard() { - return <h1>Placeholder</h1>; + const [isLoading, setIsLoading] = useState<boolean>(true); + const [robots, setRobots] = useState<Robot[]>([]); + + const navigate = useNavigate(); + + const userString = localStorage.getItem("user"); + const user: AuthorizedUser = userString ? JSON.parse(userString) : null; + const token = localStorage.getItem("token-robot-tracker"); + + async function handleLogout() { + localStorage.removeItem("token-robot-tracker"); + localStorage.removeItem("user"); + navigate("/login", { replace: true }); + } + + useEffect(() => { + // Additional safety check to protect this page from unauthorized access + if (!token || token === "undefined" || token === "null") { + navigate("/login"); + return; + } + + // Request robot data from backend + async function fetchRobots() { + try { + setIsLoading(true); + + const response = await fetch(`${API_URL}/robots`, { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorData: ErrorResponse = await response.json(); + throw new Error( + errorData.message || + `Failed to load the robots: ${response.status}` + ); + } + + const data: RobotsResponse = await response.json(); + setRobots(data.data); + } catch (error) { + console.error("Failed to load the robots:", error); + } finally { + setIsLoading(false); + } + } + + fetchRobots(); + + // Establish WebSocket connection to backend + const socket = io(API_URL); + + // Listen for real-time robot updates + socket.on("robots_update", (updatedRobots) => { + setRobots(updatedRobots); + }); + + // Cleanup when component unmounts + return () => { + socket.disconnect(); + }; + }, [token, navigate]); + + return isLoading ? ( + <FadeLoader /> + ) : ( + <div className="dashboard-page"> + <CityMap robots={robots} /> + <Header user={user} logout={handleLogout} /> + </div> + ); } export default Dashboard; |
