浏览代码

introduce a logout page and the navbar

Sven Czarnian 2 年之前
父节点
当前提交
54b9b0245a
共有 2 个文件被更改,包括 163 次插入0 次删除
  1. 22 0
      src/components/logout.tsx
  2. 141 0
      src/components/navbar.tsx

+ 22 - 0
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 <></>;
+}

+ 141 - 0
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<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} /> : <></>);
+};