diff --git a/atciss-frontend/src/components/LoaRow.tsx b/atciss-frontend/src/components/LoaRow.tsx index 33276e18..8b7316ec 100644 --- a/atciss-frontend/src/components/LoaRow.tsx +++ b/atciss-frontend/src/components/LoaRow.tsx @@ -34,10 +34,16 @@ const PositionInformation = ({ : `${sector}${frequency}` } -export const LoaRow = ({ loa }: { loa: LoaItem }) => { +export const LoaRow = ({ + loa, + showCop = true, +}: { + loa: LoaItem + showCop?: boolean +}) => { return ( - {loa.cop} + {showCop && {loa.cop}} {loa.adep_ades === "ADEP" && <>↗} {loa.adep_ades === "ADES" && <>↘} {loa.aerodrome} diff --git a/atciss-frontend/src/components/map/AreaLayer.tsx b/atciss-frontend/src/components/map/AreaLayer.tsx index b50e6ff5..b8209e06 100644 --- a/atciss-frontend/src/components/map/AreaLayer.tsx +++ b/atciss-frontend/src/components/map/AreaLayer.tsx @@ -1,6 +1,6 @@ import { LayerGroup, Polygon, Tooltip } from "react-leaflet" import { useAppSelector } from "../../app/hooks" -import { selectAreasOnMap, selectLevel } from "../../services/mapSlice" +import { selectLevel } from "../../services/mapSlice" import { AreaBooking, usePollAreas } from "../../services/areaApi" import { Box, Text } from "theme-ui" import { z3 } from "../../app/utils" @@ -10,7 +10,6 @@ export const AreaLayer = () => { const { data: areas } = usePollAreas() const level = useAppSelector(selectLevel) - const displayAreas = useAppSelector(selectAreasOnMap) const levelFilter = (a: AreaBooking) => (a.lower_limit ?? 0) <= level && level < (a.upper_limit ?? 999) @@ -21,54 +20,53 @@ export const AreaLayer = () => { return ( - {displayAreas && - areas - ?.filter(levelFilter) - .filter(isActive) - .map((area) => { - const start = DateTime.fromISO(area.start_datetime).toUTC() - const end = DateTime.fromISO(area.end_datetime).toUTC() - const active = DateTime.utc() >= start + {areas + ?.filter(levelFilter) + .filter(isActive) + .map((area) => { + const start = DateTime.fromISO(area.start_datetime).toUTC() + const end = DateTime.fromISO(area.end_datetime).toUTC() + const active = DateTime.utc() >= start - return ( - - - - {area.name} - - - FL{z3(area.lower_limit ?? 0)}-FL - {z3(area.upper_limit ?? 660)} - - - - {active - ? `Active, deactivates ${end.toRelative()}` - : `Will be active ${start.toRelative()}`} - {" "} - - - {`${start.toFormat("y-MM-dd HH:mm")}-${end.toFormat( - "y-MM-dd HH:mm", - )}`} - - - - ) - })} + return ( + + + + {area.name} + + + FL{z3(area.lower_limit ?? 0)}-FL + {z3(area.upper_limit ?? 660)} + + + + {active + ? `Active, deactivates ${end.toRelative()}` + : `Will be active ${start.toRelative()}`} + {" "} + + + {`${start.toFormat("y-MM-dd HH:mm")}-${end.toFormat( + "y-MM-dd HH:mm", + )}`} + + + + ) + })} ) } diff --git a/atciss-frontend/src/components/map/NavaidLayer.tsx b/atciss-frontend/src/components/map/LoaNavaidLayer.tsx similarity index 94% rename from atciss-frontend/src/components/map/NavaidLayer.tsx rename to atciss-frontend/src/components/map/LoaNavaidLayer.tsx index 507fea4f..57612611 100644 --- a/atciss-frontend/src/components/map/NavaidLayer.tsx +++ b/atciss-frontend/src/components/map/LoaNavaidLayer.tsx @@ -5,7 +5,7 @@ import { loaApi, selectLoaCops } from "../../services/loaApi" import { useAppSelector } from "../../app/hooks" import { selectOwnedSectors } from "../../services/activePositionSlice" -export const NavaidLayer = () => { +export const LoaNavaidLayer = () => { const ownedSectors = useAppSelector(selectOwnedSectors) loaApi.useGetBySectorsQuery(ownedSectors, { skip: ownedSectors.length == 0, diff --git a/atciss-frontend/src/components/map/MapControls.tsx b/atciss-frontend/src/components/map/MapControls.tsx index 33ae0493..7d2648a5 100644 --- a/atciss-frontend/src/components/map/MapControls.tsx +++ b/atciss-frontend/src/components/map/MapControls.tsx @@ -5,12 +5,14 @@ import { selectAreasOnMap, selectDFSOnMap, selectDWDOnMap, + selectLoaOnMap, selectOpenFlightmapsOnMap, selectSatelliteOnMap, selectSectorsOnMap, setAreas, setDFS, setDWD, + setLoa, setOpenFlightmaps, setSatellite, setSectors, @@ -29,6 +31,7 @@ export const MapControls = () => { const satellite = useAppSelector(selectSatelliteOnMap) const sectors = useAppSelector(selectSectorsOnMap) const areas = useAppSelector(selectAreasOnMap) + const loa = useAppSelector(selectLoaOnMap) return ( <> @@ -92,7 +95,17 @@ export const MapControls = () => { Sectors - {(areas || sectors) && } + + + dispatch(setLoa(e.target.checked))} + /> + LOA + + + {(areas || sectors || loa) && } {sectors && } ) diff --git a/atciss-frontend/src/components/map/NavaidMarker.tsx b/atciss-frontend/src/components/map/NavaidMarker.tsx index 014a5ba8..3192466b 100644 --- a/atciss-frontend/src/components/map/NavaidMarker.tsx +++ b/atciss-frontend/src/components/map/NavaidMarker.tsx @@ -1,9 +1,17 @@ +/** @jsxImportSource theme-ui */ + import L, { LatLngExpression } from "leaflet" -import { Marker } from "react-leaflet" -import { selectLOANavaid } from "../../services/navaidApi" +import { Marker, Tooltip } from "react-leaflet" +import { selectLoaNavaid } from "../../services/navaidApi" import { useAppSelector } from "../../app/hooks" import { ReactElement } from "react" import { createPortal } from "react-dom" +import { Box, Flex, Text } from "theme-ui" +import { LoaRow } from "../LoaRow" +import { + selectEntryLoasByNavaid, + selectExitLoasByNavaid, +} from "../../services/loaApi" const icons: { [key: string]: ReactElement } = { rnav: ( @@ -145,7 +153,13 @@ const icons: { [key: string]: ReactElement } = { } export const NavaidMarker = ({ designator }: { designator: string }) => { - const navaid = useAppSelector((store) => selectLOANavaid(store, designator)) + const navaid = useAppSelector((store) => selectLoaNavaid(store, designator)) + const xloasByNavaid = useAppSelector((store) => + selectExitLoasByNavaid(store, designator), + ) + const nloasByNavaid = useAppSelector((store) => + selectEntryLoasByNavaid(store, designator), + ) if (!navaid) return <> @@ -162,7 +176,7 @@ export const NavaidMarker = ({ designator }: { designator: string }) => { > {icons[navaid.type.toLowerCase()] ?? icons["rnav"]} -
{navaid.designator}
+ {navaid.designator} ) @@ -178,7 +192,70 @@ export const NavaidMarker = ({ designator }: { designator: string }) => { return ( <> {createPortal(icon, element)} - + + + + + {navaid.designator}{" "} + {navaid.designator !== navaid.name && `(${navaid.name})`} + + {(navaid.frequency || navaid.channel) && ( + + {navaid.frequency} {navaid.channel} + + )} + + + + + + + + + + + + {!!xloasByNavaid.length && ( + <> + + + + + + + {xloasByNavaid.map((loa, idx) => ( + + ))} + + + )} + {!!nloasByNavaid.length && ( + <> + + + + + + + {nloasByNavaid?.map((loa, idx) => ( + + ))} + + + )} +
ADEP/ADESFLREMARKFROMTO
Exit
Entry
+
+
) } diff --git a/atciss-frontend/src/components/map/SectorLayer.tsx b/atciss-frontend/src/components/map/SectorLayer.tsx index 24a73245..27362043 100644 --- a/atciss-frontend/src/components/map/SectorLayer.tsx +++ b/atciss-frontend/src/components/map/SectorLayer.tsx @@ -1,6 +1,5 @@ import { LayerGroup } from "react-leaflet" import { useAppSelector } from "../../app/hooks" -import { selectSectorsOnMap } from "../../services/mapSlice" import { sectorApi, selectAirportICAOs, @@ -16,14 +15,14 @@ export const SectorLayer = () => { sectorApi.useGetQuery() const sectors = useAppSelector(selectSectorIDs) - const displaySectors = useAppSelector(selectSectorsOnMap) - const airports = useAppSelector(selectAirportICAOs) usePollAtisByIcaoCodes(airports) return ( - {displaySectors && sectors.map((id) => )} + {sectors.map((id) => ( + + ))} ) } diff --git a/atciss-frontend/src/services/loaApi.ts b/atciss-frontend/src/services/loaApi.ts index dd86ef4c..c9dda327 100644 --- a/atciss-frontend/src/services/loaApi.ts +++ b/atciss-frontend/src/services/loaApi.ts @@ -102,3 +102,21 @@ export const selectLoaCops = createSelector( selectRelevantLoas, (relevantLoas) => [...new Set(relevantLoas.map((loa) => loa.cop))], ) + +export const selectExitLoasByNavaid = createCachedSelector( + [ + selectRelevantExitLoas, + (_state: RootState, designator: string) => designator, + ], + (relevantLoas, designator) => + relevantLoas.filter((loa) => loa.cop == designator), +)((_state, designator) => designator) + +export const selectEntryLoasByNavaid = createCachedSelector( + [ + selectRelevantEntryLoas, + (_state: RootState, designator: string) => designator, + ], + (relevantLoas, designator) => + relevantLoas.filter((loa) => loa.cop == designator), +)((_state, designator) => designator) diff --git a/atciss-frontend/src/services/mapSlice.ts b/atciss-frontend/src/services/mapSlice.ts index 30b134e2..0a4de2d2 100644 --- a/atciss-frontend/src/services/mapSlice.ts +++ b/atciss-frontend/src/services/mapSlice.ts @@ -10,6 +10,7 @@ type MapState = { satellite: boolean sectors: boolean areas: boolean + loa: boolean } const mapSlice = createSlice({ @@ -22,6 +23,7 @@ const mapSlice = createSlice({ satellite: localStorageOrDefault("map.satellite", false), sectors: localStorageOrDefault("map.sectors", true), areas: localStorageOrDefault("map.areas", true), + loa: localStorageOrDefault("map.loa", false), } as MapState, reducers: { setLevel(state, { payload: level }: PayloadAction) { @@ -57,6 +59,9 @@ const mapSlice = createSlice({ setAreas(state, { payload: active }: PayloadAction) { state.areas = setLocalStorage("map.areas", active) }, + setLoa(state, { payload: active }: PayloadAction) { + state.loa = setLocalStorage("map.loa", active) + }, }, }) @@ -67,6 +72,7 @@ export const selectDWDOnMap = (store: RootState) => store.map.dwd export const selectSatelliteOnMap = (store: RootState) => store.map.satellite export const selectSectorsOnMap = (store: RootState) => store.map.sectors export const selectAreasOnMap = (store: RootState) => store.map.areas +export const selectLoaOnMap = (store: RootState) => store.map.loa export const { setLevel, @@ -76,5 +82,6 @@ export const { setSatellite, setSectors, setAreas, + setLoa, } = mapSlice.actions export const { reducer: mapReducer } = mapSlice diff --git a/atciss-frontend/src/services/navaidApi.ts b/atciss-frontend/src/services/navaidApi.ts index 75cedf55..720646d6 100644 --- a/atciss-frontend/src/services/navaidApi.ts +++ b/atciss-frontend/src/services/navaidApi.ts @@ -31,14 +31,14 @@ export const navaidApi = createApi({ }), }) -const selectLOANavaids = createSelector( +const selectLoaNavaids = createSelector( (state: RootState) => state, selectLoaCops, (state, navaids) => navaidApi.endpoints.getByDesignators.select(navaids)(state)?.data ?? [], ) -export const selectLOANavaid = createCachedSelector( - [selectLOANavaids, (_state: RootState, designator: string) => designator], +export const selectLoaNavaid = createCachedSelector( + [selectLoaNavaids, (_state: RootState, designator: string) => designator], (navaids, designator) => navaids.find((n) => n.designator == designator), )((_state, designator) => designator) diff --git a/atciss-frontend/src/views/Map.tsx b/atciss-frontend/src/views/Map.tsx index 8095ffe0..783c06a0 100644 --- a/atciss-frontend/src/views/Map.tsx +++ b/atciss-frontend/src/views/Map.tsx @@ -9,37 +9,46 @@ import { BackgroundTiles } from "../components/map/BackgroundTiles" import { SectorLayer } from "../components/map/SectorLayer" import { AerodromeLayer } from "../components/map/AerodromeLayer" import { AreaLayer } from "../components/map/AreaLayer" -import { NavaidLayer } from "../components/map/NavaidLayer" +import { LoaNavaidLayer } from "../components/map/LoaNavaidLayer" +import { selectAreasOnMap, selectLoaOnMap } from "../services/mapSlice" +import { selectSectorsOnMap } from "../services/mapSlice" +import { useAppSelector } from "../app/hooks" const position = [49.2646, 11.4134] as LatLngTuple -const Map = ({ sx }: { sx?: ThemeUIStyleObject }) => ( - - - - - - - - - { + const loaOnMap = useAppSelector(selectLoaOnMap) + const sectorsOnMap = useAppSelector(selectSectorsOnMap) + const areasOnMap = useAppSelector(selectAreasOnMap) + + return ( + - - - -) + + + {sectorsOnMap && } + {areasOnMap && } + {loaOnMap && } + + + + + + + ) +} export { Map }