Skip to content

Commit

Permalink
Track selection form and fetching of init data
Browse files Browse the repository at this point in the history
  • Loading branch information
n1kPLV committed Jul 20, 2023
1 parent 026274f commit 978f9f2
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 174 deletions.
45 changes: 45 additions & 0 deletions Website/src/app/api/tracks/list/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Offer an endpoint to call in order to request a track list positions. This will
* read the auth token from the cookie, so we don't need to access it on the client
*/

import { AuthenticationRequest, AuthenticationResponse } from "@/lib/api.website";
import {getTrackList, getVehicleData} from "@/lib/data";
import { STATUS_CODES } from "http";
import { redirect } from "next/dist/server/api-utils";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import {UnauthorizedError} from "@/lib/types";

export async function GET(request: NextRequest) {
// console.log("foobar", request)
const token = cookies().get("token")?.value;
// console.log("requested track_id", track_id);

if (token) {
try {
const tracks = await getTrackList(token);
// console.log("vehicles", vehicles)
return NextResponse.json(tracks)
}
catch (e: any) {
if (e instanceof UnauthorizedError) {
// token may have expired. Delete token.
cookies().set({
name: 'token',
value: '',
sameSite: 'lax',
httpOnly: true,
expires: new Date(0)
})
console.log('UnauthorizedError')
return new NextResponse('Unauthorized', {status: 401})
} else
return new NextResponse("Error" + e.toString(), {status: 500})
}
}
else {
return new NextResponse("Unauthorized", {status: 401})
}

}
31 changes: 17 additions & 14 deletions Website/src/app/map/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,37 @@

import DynamicMap from '@/components/dynmap';
import {cookies} from 'next/headers';
import {getVehicleData} from '@/lib/data';
import {getInitData, getVehicleData} from '@/lib/data';
import {LoginDialog} from "@/components/login";
import LoginMapWrapper from "@/components/login_map";

const getInitData = async (context: {token?: string, track_id: number}) => {
// TODO:
}
import {InitResponse, Vehicle} from "@/lib/api.website";

export default async function Home() {

const token = cookies().get("token")?.value;
const track_id = 0
const server_vehicles = token ? await getVehicleData(token, track_id) : [];
const track_id = parseInt(cookies().get("track_id")?.value ?? '', 10)
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) : [];
} catch (e) {
console.log('Catched e');
init_data = undefined;
server_vehicles = []
}


console.log("server vehicles", server_vehicles)
return (
<div className='h-full min-h-screen'>
<LoginMapWrapper logged_in={token !== undefined} map_conf={
<LoginMapWrapper logged_in={token !== undefined} track_selected={!isNaN(track_id)} map_conf={
{
position: {lat: 54.2333, lng: 10.6024},
zoom_level: 11,
server_vehicles,
track_id
track_id,
init_data
}
} />
<footer>
Foo Bar Baz - Footer Text
</footer>
</div>
)
}
131 changes: 66 additions & 65 deletions Website/src/components/dynmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,81 @@
import dynamic from 'next/dynamic';
import LoadMapScreen from './loadmap';
import {Vehicle} from "@/lib/api.website";
import {IMapConfig, IMapRefreshConfig} from '@/lib/types';
import {IMapConfig, IMapRefreshConfig, RevalidateError} from '@/lib/types';
import {useEffect, useRef, useState} from 'react';
import {clearInterval, setInterval} from 'timers';
import {TTuple} from "ts-interface-checker";
import useSWR from "swr";

const _internal_DynamicMap = dynamic(() => import('@/components/map'), {
loading: LoadMapScreen,
ssr: false
loading: LoadMapScreen,
ssr: false
});

export default function DynamicMap(props: React.PropsWithChildren<IMapRefreshConfig & {logged_in: boolean}>) {

const { position, zoom_level, server_vehicles, track_id, logged_in } = props;
// console.log(props)
var i = 0
const fetcher = ([url, track_id]: [url: string, track_id: number]) => {
return fetch(url, {method: 'post', body: JSON.stringify({track_id})}).then(
async (res: Response) => {
if (!res.ok) {
// console.log('not ok!');
throw new RevalidateError('Re-Fetching unsuccessful', res.status);
}
//console.log('ok')
return res;
}
).then(res => res.json())
.then(res => {
// console.log(res);
const test_vehicle: Vehicle = {
id: 0,
pos: {
lat: 54.17 + 0.05 * Math.cos(i * Math.PI / 180),
lng: 10.56 + 0.085 * Math.sin(i * Math.PI / 180)
},
heading: i + 90,
name: 'foo',
batteryLevel: 0.5
};
// {id: 42, pos: {lat: 54.2 + 0.05 * Math.cos((i.current + 180) * Math.PI / 180), lng: 10.56 + 0.085 * Math.sin((i.current + 180) * Math.PI / 180) }, heading: i.current - 90, name: 'bar', batteryLevel: 1}
// ];
i += 5.1;
return res.concat([test_vehicle])
});
};

const [vehicles, setVehicles] = useState(server_vehicles)
// const timeoutRef = useRef(undefined as NodeJS.Timeout | undefined);
export default function DynamicMap(props: React.PropsWithChildren<IMapRefreshConfig & {
logged_in: boolean,
setLogin: (success: boolean) => void
}>) {

const i = useRef(1)
async function updateVehicles() {
const test_vehicle: Vehicle = {id: 0, pos: {lat: 54.17 + 0.05 * Math.cos(i.current * Math.PI / 180), lng: 10.56 + 0.085 * Math.sin(i.current * Math.PI / 180)}, heading: i.current + 90, name: 'foo', batteryLevel: 0.5};
// {id: 42, pos: {lat: 54.2 + 0.05 * Math.cos((i.current + 180) * Math.PI / 180), lng: 10.56 + 0.085 * Math.sin((i.current + 180) * Math.PI / 180) }, heading: i.current - 90, name: 'bar', batteryLevel: 1}
// ];
i.current+=5.1;
let real_vehicles: Vehicle[]
const x = await fetch(`/api/update`, { cache: 'no-store', method: "POST", body: JSON.stringify({"track_id": track_id}) })
if (x.ok) {
// debugger;
real_vehicles = await x.json();
} else {
console.log("Could not fetch vehicle positions", x.status, x.statusText)
real_vehicles = []
}
// debugger;
real_vehicles = real_vehicles.concat([test_vehicle]);
console.log('Updating vehicle positions!', real_vehicles);
setVehicles(real_vehicles);
}

const {position, zoom_level, server_vehicles, track_id, logged_in, init_data} = props;
// console.log(props)

useEffect(() => {
if (!logged_in) {
return;
}
console.log("Effect");
// debugger;
// if (1 || !timeoutRef.current)
// timeoutRef.current = new Promise(resolve => setTimeout(resolve, 1000)).then(
// updateVehicles
// ).then(
// async () => {
// console.log("Foo!");
// await undefined;
// }
// )
// timeoutRef.current = setTimeout(() => {
// console.log("timeout!!"); updateVehicles().catch(() => {}).then()
// }, 1000);
// return () => {
// console.log("Cancelled!");
// clearTimeout(timeoutRef.current);
// timeoutRef.current = undefined;
// };
const interval = setInterval(() => updateVehicles().catch(console.error), 1000);
return () => {
console.log("effect cancelled");
clearInterval(interval);
// const [vehicles, setVehicles] = useState(server_vehicles)
// const timeoutRef = useRef(undefined as NodeJS.Timeout | undefined);

const {data, error, isLoading} = useSWR(['/api/update', track_id], fetcher, {
refreshInterval: 1000,
isOnline: () => logged_in
})

// console.log(data, error, isLoading);

const vehicles = (isLoading || error) ? server_vehicles : data;

if (logged_in && error) {
if (error instanceof RevalidateError && error.statusCode == 401) {
console.log('Invalid token');
window.location.reload();
}
console.log("revalidate error", error)
}
})

return (
<div style={{ height: '90vh' }}>
<_internal_DynamicMap
position={position} zoom_level={zoom_level} server_vehicles={vehicles}
/>
</div>

return (
<div className={'h-96 grow'}>
<_internal_DynamicMap
position={position} zoom_level={zoom_level} server_vehicles={vehicles} init_data={init_data}
/>
</div>
)
}
Empty file added Website/src/components/form.tsx
Empty file.
10 changes: 8 additions & 2 deletions Website/src/components/login_map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import {type IMapConfig, IMapRefreshConfig} from "@/lib/types";
import {PropsWithChildren, useState} from "react";
import {LoginDialog} from "@/components/login";
import DynamicMap from "@/components/dynmap";
import {SelectionDialog} from "@/components/track_selection";

const LoginMapWrapper = ({logged_in, map_conf}: PropsWithChildren<{logged_in: boolean, map_conf: IMapRefreshConfig}>) => {
const LoginMapWrapper = ({logged_in, track_selected, map_conf}: PropsWithChildren<{logged_in: boolean, track_selected: boolean, map_conf: IMapRefreshConfig}>) => {
const [loginState, setLogin] = useState(logged_in);

console.log('track selected', track_selected, map_conf.track_id)

return <>
{!loginState &&
<LoginDialog dst_url='/map' login_callback={setLogin}>
<p className="mb-1.5">You need to log in!</p>
</LoginDialog>}
<DynamicMap {...map_conf} logged_in={loginState}/>
{loginState && !track_selected && <SelectionDialog dst_url='/map' login_callback={setLogin}>
<p className="mb-1.5">Please select a track!</p>
</SelectionDialog> }
<DynamicMap {...map_conf} logged_in={loginState} setLogin={setLogin}/>
</>
}

Expand Down
Loading

0 comments on commit 978f9f2

Please sign in to comment.