diff --git a/Website/src/app/map/page.tsx b/Website/src/app/map/page.tsx index 110d7a73..2bfa0a58 100644 --- a/Website/src/app/map/page.tsx +++ b/Website/src/app/map/page.tsx @@ -4,35 +4,40 @@ import DynamicMap from '@/components/dynmap'; import {cookies} from 'next/headers'; import {getInitData, getVehicleData} from '@/lib/data'; import {LoginDialog} from "@/components/login"; -import LoginMapWrapper from "@/components/login_map"; +import LoginWrapper from "@/components/login_wrap"; import {InitResponse, Vehicle} from "@/lib/api.website"; +import {nanToUndefined} from "@/lib/helpers"; -export default async function Home() { +export default async function Home({searchParams}: { searchParams: { focus?: string, success?: string } }) { - const token = cookies().get("token")?.value; - const track_id = parseInt(cookies().get("track_id")?.value ?? '', 10) - let server_vehicles: Vehicle[]; - let init_data: InitResponse | undefined; + console.log('params', searchParams); + + const token = cookies().get("token")?.value; + const track_id = parseInt(cookies().get("track_id")?.value ?? '', 10) + const track_selected = !isNaN(track_id); + let server_vehicles: Vehicle[]; + let init_data: InitResponse | undefined; try { - init_data = token ? await getInitData(token, track_id) : undefined; - server_vehicles = token ? await getVehicleData(token, track_id) : []; + init_data = (token && track_selected) ? await getInitData(token, track_id) : undefined; + server_vehicles = (token && track_selected) ? await getVehicleData(token, track_id) : []; } catch (e) { - console.log('Catched e'); + console.log('Catched e:', e); init_data = undefined; server_vehicles = [] } + const focus = nanToUndefined(parseInt(searchParams.focus ?? '', 10)); - - console.log("server vehicles", server_vehicles) - return ( - - ) + console.log("server vehicles", server_vehicles) + return ( + + ) } diff --git a/Website/src/components/dynmap.tsx b/Website/src/components/dynmap.tsx index 80c8432f..06c7ab6f 100644 --- a/Website/src/components/dynmap.tsx +++ b/Website/src/components/dynmap.tsx @@ -44,25 +44,21 @@ const fetcher = ([url, track_id]: [url: string, track_id: number]) => { }); }; -export default function DynamicMap(props: React.PropsWithChildren void -}>) { +export default function DynamicMap(props: IMapRefreshConfig) { - const {position, zoom_level, server_vehicles, track_id, logged_in, init_data} = props; + const {position, zoom_level, server_vehicles, track_id, logged_in, init_data, focus} = props; // console.log(props) // const [vehicles, setVehicles] = useState(server_vehicles) // const timeoutRef = useRef(undefined as NodeJS.Timeout | undefined); - const {data, error, isLoading} = useSWR(['/api/update', track_id], fetcher, { + const {data, error, isLoading} = useSWR((logged_in && track_id) ? ['/api/update', track_id] : null, fetcher, { refreshInterval: 1000, - isOnline: () => logged_in }) // console.log(data, error, isLoading); - const vehicles = (isLoading || error) ? server_vehicles : data; + const vehicles = (isLoading || error || !logged_in || !track_id) ? server_vehicles : data; if (logged_in && error) { if (error instanceof RevalidateError && error.statusCode == 401) { @@ -75,7 +71,7 @@ export default function DynamicMap(props: React.PropsWithChildren <_internal_DynamicMap - position={position} zoom_level={zoom_level} server_vehicles={vehicles} init_data={init_data} + position={position} zoom_level={zoom_level} server_vehicles={vehicles} init_data={init_data} focus={focus} /> ) diff --git a/Website/src/components/login_map.tsx b/Website/src/components/login_wrap.tsx similarity index 59% rename from Website/src/components/login_map.tsx rename to Website/src/components/login_wrap.tsx index 1b29ecb7..0106d0d5 100644 --- a/Website/src/components/login_map.tsx +++ b/Website/src/components/login_wrap.tsx @@ -5,21 +5,21 @@ import {LoginDialog} from "@/components/login"; import DynamicMap from "@/components/dynmap"; import {SelectionDialog} from "@/components/track_selection"; -const LoginMapWrapper = ({logged_in, track_selected, map_conf}: PropsWithChildren<{logged_in: boolean, track_selected: boolean, map_conf: IMapRefreshConfig}>) => { +const LoginWrapper = ({logged_in, track_selected, map_conf, child}: {logged_in: boolean, track_selected: boolean, map_conf: IMapRefreshConfig, child: (conf: IMapRefreshConfig) => JSX.Element}) => { const [loginState, setLogin] = useState(logged_in); console.log('track selected', track_selected, map_conf.track_id) return <> {!loginState && - +

You need to log in!

} - {loginState && !track_selected && + {loginState && !track_selected &&

Please select a track!

} - + {child({...map_conf, logged_in: loginState, setLogin: setLogin})} } -export default LoginMapWrapper; \ No newline at end of file +export default LoginWrapper; \ No newline at end of file diff --git a/Website/src/components/map.tsx b/Website/src/components/map.tsx index 9b083a64..7c075cc3 100644 --- a/Website/src/components/map.tsx +++ b/Website/src/components/map.tsx @@ -6,20 +6,7 @@ import {useEffect, useRef} from "react"; import {createRoot} from "react-dom/client"; import {IMapConfig} from '@/lib/types' import {Vehicle} from "@/lib/api.website"; - -const batteryLevelFormatter = new Intl.NumberFormat('de-DE', { - notation: "standard", - style: 'unit', - unit: 'percent', - maximumFractionDigits: 1, -}) - -const coordinateFormatter = new Intl.NumberFormat('de-DE', { - notation: "standard", - style: 'unit', - unit: 'degree', - maximumFractionDigits: 2, -}) +import {batteryLevelFormatter, coordinateFormatter} from "@/lib/helpers"; function popupContent({batteryLevel, name, pos}: Vehicle): L.Content { const baseContainer = document.createElement('div') @@ -44,7 +31,7 @@ function Map(props: IMapConfig) { // console.log('props', props); - const {position, zoom_level, server_vehicles, init_data} = props; + const {position, zoom_level, server_vehicles, init_data, focus} = props; const mapRef = useRef(undefined as L.Map | undefined); const markerRef = useRef([] as L.Marker[]) @@ -89,6 +76,10 @@ function Map(props: IMapConfig) { }).addTo(mapRef.current); m.bindPopup(popupContent(v)) m.setRotationAngle(v.heading || 0) + if (v.id === focus) { + m.openPopup(); + mapRef.current?.setView(m.getLatLng()); + } markerRef.current.push(m); } mapRef.current.setView(position, zoom_level); @@ -114,6 +105,10 @@ function Map(props: IMapConfig) { m.setLatLng(vehicles[i].pos) m.setPopupContent(popupContent(vehicles[i])) m.setRotationAngle(vehicles[i].heading || 0) + if (vehicles[i].id === focus) { + m.openPopup(); + mapRef.current?.setView(m.getLatLng()); + } // L.circle(vehicles[i].pos, {radius: 0.5, color: '#009988'}).addTo(mapRef.current); } else { const m = L.marker(vehicles[i].pos, { @@ -123,6 +118,10 @@ function Map(props: IMapConfig) { markerRef.current.push(m); m.bindPopup(popupContent(vehicles[i])) m.setRotationAngle(vehicles[i].heading || 0) + if (vehicles[i].id === focus) { + m.openPopup(); + mapRef.current?.setView(m.getLatLng()); + } } } diff --git a/Website/src/components/track_selection.tsx b/Website/src/components/track_selection.tsx index 4aa1690b..50895f33 100644 --- a/Website/src/components/track_selection.tsx +++ b/Website/src/components/track_selection.tsx @@ -41,13 +41,13 @@ export default function Selection({dst_url}: {dst_url?: Url}) { return (
- {isLoading ?

Lädt...

: (<> + {isLoading ?

Lädt...

: (error ?

{error.toString()}

: (<> - )} + ))}
) } diff --git a/Website/src/lib/api.website.ts b/Website/src/lib/api.website.ts index 70cafaef..721fcec5 100644 --- a/Website/src/lib/api.website.ts +++ b/Website/src/lib/api.website.ts @@ -88,7 +88,7 @@ export interface VehicleCrU { uid?: number, // Null, if creating vehicle, some other value otherwise name: string, // The name, that is attached to the vehicle, e.g. "1" for "Draisine 1" typeId: number, // The id of the type - trackerIds?: string[]// A unique id to identify the tracker belonging to that vehicle + trackerIds: string[]// A unique id to identify the tracker belonging to that vehicle } export interface VehicleTypeListItem { diff --git a/Website/src/lib/helpers.ts b/Website/src/lib/helpers.ts index 3fef6049..54d04545 100644 --- a/Website/src/lib/helpers.ts +++ b/Website/src/lib/helpers.ts @@ -1,2 +1,23 @@ -export const async_sleep: (time: number) => Promise = (time) => new Promise((resolve, reject) => setTimeout(() => resolve(null), time)) \ No newline at end of file +export const async_sleep: (time: number) => Promise = (time) => new Promise((resolve, reject) => setTimeout(() => resolve(null), time)) + +export const batteryLevelFormatter = new Intl.NumberFormat('de-DE', { + notation: "standard", + style: 'unit', + unit: 'percent', + maximumFractionDigits: 1, +}) + +export const coordinateFormatter = new Intl.NumberFormat('de-DE', { + notation: "standard", + style: 'unit', + unit: 'degree', + maximumFractionDigits: 2, +}) + +export function nanToUndefined(x: number): number | undefined { + if (Number.isNaN(x)) + return; + return x; + +} \ No newline at end of file diff --git a/Website/src/lib/types.ts b/Website/src/lib/types.ts index c9e75b16..5f05393b 100644 --- a/Website/src/lib/types.ts +++ b/Website/src/lib/types.ts @@ -6,10 +6,13 @@ export interface IMapConfig { zoom_level: number, server_vehicles: Vehicle[], init_data?: InitResponse + focus?: number } export interface IMapRefreshConfig extends IMapConfig { track_id: number + logged_in?: boolean, + setLogin?: (success: boolean) => void } export class UnauthorizedError extends Error {}