From e836e7dd4ed5e9fa60e949d159100040b22a8f48 Mon Sep 17 00:00:00 2001 From: Arne Rief Date: Mon, 22 Dec 2025 21:20:39 +0100 Subject: Movement simulator for all and single robot, project v1 ready --- frontend/src/components/RobotList.tsx | 98 +++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) (limited to 'frontend/src/components/RobotList.tsx') diff --git a/frontend/src/components/RobotList.tsx b/frontend/src/components/RobotList.tsx index d711372..21d8e63 100644 --- a/frontend/src/components/RobotList.tsx +++ b/frontend/src/components/RobotList.tsx @@ -1,11 +1,22 @@ -import { useState } from "react"; -import type { Robot } from "../types/robot"; +import { + useState, + type Dispatch, + type MouseEvent, + type SetStateAction, +} from "react"; +import type { ErrorResponse } from "../types/error"; +import type { Robot, SimulationResponse } from "../types/robot"; type ExpandedRobotsState = Record; -type Props = { robots: Robot[]; }; +type Props = { + apiUrl: string; + robots: Robot[]; + token: string | null; + setErrorMessage: Dispatch>; +}; -function RobotList({ robots }: Props) { +function RobotList({ apiUrl, robots, token, setErrorMessage }: Props) { const [expandedRobots, setExpandedRobots] = useState( {} ); @@ -17,15 +28,89 @@ function RobotList({ robots }: Props) { })); } + // Move or stop individual robot + async function controlSingleRobot( + event: MouseEvent, + robotId: number, + robotStatus: Robot["status"] + ) { + const isRobotMoving = robotStatus === "moving"; + const button = event.currentTarget; + button.disabled = true; // prevent spamming + + try { + // Make button clickable again after 1 second + setTimeout(() => { + button.disabled = false; + }, 1000); + + const response = await fetch( + `${apiUrl}/robots/${robotId}/${ + isRobotMoving ? "stop" : "move" + }`, + { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + const errorData: ErrorResponse = await response.json(); + throw new Error( + errorData.message || + `Failed to ${ + isRobotMoving ? "stop" : "start" + } robot ID ${robotId}.` + ); + } + + const data: SimulationResponse = await response.json(); + console.log(data.message); + } catch (error) { + console.error( + `Error ${ + isRobotMoving ? "stopping" : "starting" + } robot ID ${robotId}: `, + error + ); + + if (error instanceof Error) { + setErrorMessage(error.message); + } else { + setErrorMessage("An unexpected error occurred."); + } + } + } + return (
    - {robots.map((robot) => { + {robots?.map((robot) => { const isExpanded = expandedRobots[robot?.id]; return (
  • {robot?.name}

    + {/* Move/stop individual robot */} + + + {/* Movement status */}

    Status:{" "} @@ -33,12 +118,14 @@ function RobotList({ robots }: Props) {

    + {/* Current position */}

    Position:

    • Lat: {robot?.lat}
    • Lon: {robot?.lon}
    + {/* Expand position log */} + {/* Position log/history */}