|
@@ -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<string>('');
|
|
|
+ const [menuTree, setMenuTree] = useState<any>();
|
|
|
+ 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 !== '' ? <div>{fullName}</div> : <></>
|
|
|
+ );
|
|
|
+
|
|
|
+ return (fullName !== '' && menuTree.length !== 0 ? <Menubar model={menuTree} end={username} /> : <></>);
|
|
|
+};
|