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