From 237f8ae6c29bbf485c312b2fed4d5ab4f99a4eff Mon Sep 17 00:00:00 2001
From: Arne Rief <riearn@proton.me>
Date: Sat, 20 Dec 2025 14:09:20 +0100
Subject: Map and loading robots

---
 frontend/src/pages/Dashboard.tsx | 89 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

(limited to 'frontend/src/pages/Dashboard.tsx')

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;
-- 
cgit v1.2.3

