introduce a logout page and the navbar
This commit is contained in:
22
src/components/logout.tsx
Normal file
22
src/components/logout.tsx
Normal file
@@ -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 <></>;
|
||||
}
|
||||
141
src/components/navbar.tsx
Normal file
141
src/components/navbar.tsx
Normal file
@@ -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} /> : <></>);
|
||||
};
|
||||
Reference in New Issue
Block a user