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 (
)
}
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 {}