From 54b9b0245a7f339fd282e030880964d0a9788c2b Mon Sep 17 00:00:00 2001 From: Sven Czarnian Date: Thu, 3 Nov 2022 23:38:31 +0100 Subject: [PATCH] introduce a logout page and the navbar --- src/components/logout.tsx | 22 ++++++ src/components/navbar.tsx | 141 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/components/logout.tsx create mode 100644 src/components/navbar.tsx diff --git a/src/components/logout.tsx b/src/components/logout.tsx new file mode 100644 index 0000000..132b1e4 --- /dev/null +++ b/src/components/logout.tsx @@ -0,0 +1,22 @@ +import React, { useContext } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { AuthContext } from '../contexts'; + +export const Logout: React.FC = () => { + const context = useContext(AuthContext); + const navigate = useNavigate(); + + context.setAuth({ + valid: false, + user: { + vatsimId: '', + fullName: '', + administrator: false, + airportConfigurationAccess: [], + }, + }); + sessionStorage.removeItem('token'); + navigate('/'); + + return <>; +} diff --git a/src/components/navbar.tsx b/src/components/navbar.tsx new file mode 100644 index 0000000..dbdc177 --- /dev/null +++ b/src/components/navbar.tsx @@ -0,0 +1,141 @@ +import { Menubar } from 'primereact/menubar'; +import React, { useContext, useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { AuthContext } from '../contexts'; +import { Configuration } from '../services'; +import { Airport } from '../services'; +import { AirportOverview } from '../types'; + +export const NavBar: React.FC = () => { + const [fullName, setFullName] = useState(''); + const [menuTree, setMenuTree] = useState(); + const context = useContext(AuthContext); + const navigate = useNavigate(); + + const firBasedSubMenu = (airports: AirportOverview[], endpoint: string): any[] => { + if (airports.length === 0) { + return [{ + label: 'No airport available', + disabled: true, + }]; + } + + const firAirports: [string, AirportOverview[]][] = []; + + // cluster airports based on FIRs + airports.forEach((airport) => { + const idx = firAirports.findIndex((value) => value[0] === airport.flightInformationRegion); + if (idx !== -1) { + firAirports[idx][1].push(airport); + } else { + firAirports.push([airport.flightInformationRegion, [airport]]); + } + }); + + // create the submenu for every FIR + const retval: any[] = []; + firAirports.forEach((fir) => { + retval.push({ + label: fir[0], + items: [], + }); + + // sort airports alphabetically + fir[1].sort(); + + // create the airport with the link + fir[1].forEach((airport) => { + retval[retval.length - 1].push({ + label: `${airport.icao} - ${airport.name}`, + command: () => navigate(`${endpoint}?icao=${airport.icao}`), + }); + }); + }); + + return retval; + } + + const updateMenuItems = async () => { + Airport.all().then((airports) => { + const newMenuTree: { label: string; items?: any[]; command?: () => void }[] = [ + { + label: 'Airports', + items: [] as any[], + } + ]; + + // create the airports subtree + const airportSubtree = firBasedSubMenu(airports, '/sequence'); + newMenuTree[0].items = airportSubtree; + + // collect all configuration airports + const configurationAirports: AirportOverview[] = []; + airports.forEach((airport) => { + const idx = context.auth.user.airportConfigurationAccess.findIndex((value) => airport.icao === value); + if (idx !== -1) configurationAirports.push(airport); + }); + + // create the configuration subtree + if (configurationAirports.length !== 0) { + const configurationSubtree = firBasedSubMenu(configurationAirports, '/configure/airport'); + newMenuTree[1].items = configurationSubtree; + } + + if (context.auth.user.administrator) { + newMenuTree.push({ + label: 'Administration', + items: [ + { + label: 'Users', + command: () => navigate('/admin/users'), + }, + { + label: 'Airports', + command: () => navigate('/admin/airports'), + }, + ], + }); + } + + newMenuTree.push({ + label: 'Logout', + command: () => navigate('/logout'), + }); + + setMenuTree(newMenuTree); + }); + } + + useEffect(() => { + const event = new EventSource(`${Configuration.resourceServer}/airport/renew`); + event.onmessage = () => { + updateMenuItems(); + } + + return () => { + event.close(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (context.auth.valid) { + if (context.auth.user.fullName !== '') { + setFullName(context.auth.user.fullName); + } else { + setFullName(context.auth.user.vatsimId); + } + updateMenuItems(); + } else { + setFullName(''); + setMenuTree([]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [context]); + + const username = ( + fullName !== '' ?
{fullName}
: <> + ); + + return (fullName !== '' && menuTree.length !== 0 ? : <>); +};