navbar.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { Menubar } from 'primereact/menubar';
  2. import React, { useContext, useEffect, useRef, useState } from 'react';
  3. import { useNavigate } from 'react-router-dom';
  4. import { AuthContext } from '../contexts';
  5. import { Configuration } from '../services';
  6. import { Airport } from '../services';
  7. import { AirportOverview, BackendReturnStatus, IAuthState } from '../types';
  8. export const NavBar: React.FC = () => {
  9. const [menuTree, setMenuTree] = useState<any>(undefined);
  10. const authContext = useContext(AuthContext);
  11. const currentAuth = useRef<IAuthState>();
  12. const navigate = useNavigate();
  13. currentAuth.current = authContext.auth;
  14. const firBasedSubMenu = (airports: AirportOverview[], endpoint: string): any[] => {
  15. if (airports.length === 0) {
  16. return [{
  17. label: 'No airport available',
  18. disabled: true,
  19. }];
  20. }
  21. const firAirports: [string, AirportOverview[]][] = [];
  22. // cluster airports based on FIRs
  23. airports.forEach((airport) => {
  24. const idx = firAirports.findIndex((value) => value[0] === airport.flightInformationRegion);
  25. if (idx !== -1) {
  26. firAirports[idx][1].push(airport);
  27. } else {
  28. firAirports.push([airport.flightInformationRegion, [airport]]);
  29. }
  30. });
  31. // create the submenu for every FIR
  32. const retval: any[] = [];
  33. firAirports.forEach((fir) => {
  34. retval.push({
  35. label: fir[0],
  36. items: [],
  37. });
  38. // sort airports alphabetically
  39. fir[1].sort();
  40. // create the airport with the link
  41. fir[1].forEach((airport) => {
  42. retval[retval.length - 1].push({
  43. label: `${airport.icao} - ${airport.name}`,
  44. command: () => navigate(`${endpoint}?icao=${airport.icao}`),
  45. });
  46. });
  47. });
  48. return retval;
  49. }
  50. const updateMenuItems = async () => {
  51. if (currentAuth.current === undefined || !currentAuth.current.valid) return [];
  52. Airport.all().then((response) => {
  53. if (response.status !== BackendReturnStatus.Ok) return [];
  54. const newMenuTree: { label: string; items?: any[]; command?: () => void }[] = [
  55. {
  56. label: 'Airports',
  57. items: [] as any[],
  58. }
  59. ];
  60. // create the airports subtree
  61. const airportSubtree = firBasedSubMenu(response.airports, '/sequence');
  62. newMenuTree[0].items = airportSubtree;
  63. // collect all configuration airports
  64. const configurationAirports: AirportOverview[] = [];
  65. response.airports.forEach((airport) => {
  66. const idx = currentAuth.current?.user.airportConfigurationAccess.findIndex((value) => airport.icao === value);
  67. if (idx !== -1) configurationAirports.push(airport);
  68. });
  69. // create the configuration subtree
  70. if (configurationAirports.length !== 0) {
  71. const configurationSubtree = firBasedSubMenu(configurationAirports, '/configure/airport');
  72. newMenuTree[1].items = configurationSubtree;
  73. }
  74. if (currentAuth.current?.user.administrator) {
  75. newMenuTree.push({
  76. label: 'Administration',
  77. items: [
  78. {
  79. label: 'Users',
  80. command: () => navigate('/admin/users'),
  81. },
  82. {
  83. label: 'Airports',
  84. command: () => navigate('/admin/airports'),
  85. },
  86. ],
  87. });
  88. }
  89. newMenuTree.push({
  90. label: 'Logout',
  91. command: () => navigate('/logout'),
  92. });
  93. setMenuTree(newMenuTree);
  94. });
  95. }
  96. useEffect(() => {
  97. const event = new EventSource(`${Configuration.resourceServer}/airport/renew`);
  98. event.onmessage = () => {
  99. updateMenuItems();
  100. }
  101. return () => {
  102. event.close();
  103. }
  104. // eslint-disable-next-line react-hooks/exhaustive-deps
  105. }, []);
  106. useEffect(() => {
  107. if (currentAuth.current?.valid) {
  108. updateMenuItems();
  109. } else {
  110. setMenuTree([]);
  111. }
  112. // eslint-disable-next-line react-hooks/exhaustive-deps
  113. }, [authContext]);
  114. if (menuTree === undefined || !currentAuth.current.valid) return <></>;
  115. return (menuTree.length !== 0 ? <Menubar model={menuTree} /> : <></>);
  116. };