164 righe
5.2 KiB
TypeScript
164 righe
5.2 KiB
TypeScript
import { Menubar } from 'primereact/menubar';
|
|
import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { AuthContext, TimeContext } from '../contexts';
|
|
import { Configuration } from '../services';
|
|
import { Airport } from '../services';
|
|
import { AirportOverview, BackendReturnStatus, IAuthState } from '../types';
|
|
|
|
export const NavBar: React.FC = () => {
|
|
const [timestamp, setTimestamp] = useState<string>('');
|
|
const [fullName, setFullName] = useState<string>('');
|
|
const [menuTree, setMenuTree] = useState<any>(undefined);
|
|
const authContext = useContext(AuthContext);
|
|
const timeContext = useContext(TimeContext);
|
|
const currentAuth = useRef<IAuthState>();
|
|
const navigate = useNavigate();
|
|
|
|
currentAuth.current = authContext.auth;
|
|
|
|
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 () => {
|
|
if (currentAuth.current === undefined || !currentAuth.current.valid) return [];
|
|
|
|
Airport.all().then((response) => {
|
|
if (response.status !== BackendReturnStatus.Ok) return [];
|
|
|
|
const newMenuTree: { label: string; items?: any[]; command?: () => void }[] = [
|
|
{
|
|
label: 'Airports',
|
|
items: [] as any[],
|
|
}
|
|
];
|
|
|
|
// create the airports subtree
|
|
const airportSubtree = firBasedSubMenu(response.airports, '/sequence');
|
|
newMenuTree[0].items = airportSubtree;
|
|
|
|
// collect all configuration airports
|
|
const configurationAirports: AirportOverview[] = [];
|
|
response.airports.forEach((airport) => {
|
|
const idx = currentAuth.current?.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 (currentAuth.current?.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();
|
|
}
|
|
|
|
const timeInterval = setInterval(() => {
|
|
const serverUtcTime = new Date(new Date().getTime() + timeContext.offset);
|
|
const hours = String(serverUtcTime.getUTCHours()).padStart(2, '0');
|
|
const minutes = String(serverUtcTime.getUTCMinutes()).padStart(2, '0');
|
|
const seconds = String(serverUtcTime.getUTCSeconds()).padStart(2, '0');
|
|
if (currentAuth.current?.valid) {
|
|
setTimestamp(`${hours}:${minutes}:${seconds}`);
|
|
}
|
|
}, 1000);
|
|
|
|
return () => {
|
|
clearInterval(timeInterval);
|
|
event.close();
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (currentAuth.current?.valid) {
|
|
if (currentAuth.current.user.fullName !== '') {
|
|
setFullName(currentAuth.current.user.fullName);
|
|
} else {
|
|
setFullName(currentAuth.current.user.vatsimId);
|
|
}
|
|
updateMenuItems();
|
|
} else {
|
|
setFullName('');
|
|
setMenuTree([]);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [authContext]);
|
|
|
|
if (menuTree === undefined || !currentAuth.current.valid) return <></>;
|
|
|
|
const rightSideInfo = (
|
|
<div>{fullName} | {timestamp}</div>
|
|
);
|
|
|
|
return (menuTree.length !== 0 ? <Menubar model={menuTree} end={rightSideInfo} /> : <></>);
|
|
};
|