Working on queries to get latest metar airports first
This commit is contained in:
4
ui/package-lock.json
generated
4
ui/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "aviation-ui",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "aviation-ui",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@mantine/core": "^7.17.2",
|
||||
"@mantine/form": "^7.17.2",
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Divider, Drawer, Group } from '@mantine/core';
|
||||
import { Box, Divider, Drawer, Group, Text } from '@mantine/core';
|
||||
import { Airport, AirportCategory } from '@lib/airport.types.ts';
|
||||
import { getMarkerColor, Metar } from '@lib/metar.types.ts';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getMetars } from '@lib/metar.ts';
|
||||
|
||||
export default function AirportDrawer({
|
||||
airport,
|
||||
@@ -8,9 +11,24 @@ export default function AirportDrawer({
|
||||
airport: Airport | null;
|
||||
setAirport: (airport: Airport | null) => void;
|
||||
}) {
|
||||
const [metar, setMetar] = useState<Metar | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (airport != null) {
|
||||
getMetars({ icaos: [airport.icao] }).then((m) => {
|
||||
if (m.length > 0) {
|
||||
setMetar(m[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [airport]);
|
||||
|
||||
if (!airport) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const metarColor = getMarkerColor(metar?.flight_category || 'UNKN');
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
opened={true}
|
||||
@@ -25,27 +43,35 @@ export default function AirportDrawer({
|
||||
withOverlay={false}
|
||||
closeOnClickOutside={false}
|
||||
>
|
||||
<Group>
|
||||
<div>ICAO: {airport.icao}</div>
|
||||
<div>Category: {airportCategoryToText(airport.category)}</div>
|
||||
<div>
|
||||
Country / Region: {airport.iso_country}, {airport.iso_region}
|
||||
</div>
|
||||
<div>Municipality: {airport.municipality || 'N/A'}</div>
|
||||
<div>Local Code: {airport.local || 'N/A'}</div>
|
||||
<div>Elevation: {airport.elevation_ft}</div>
|
||||
<div>
|
||||
Coordinates: {airport.latitude.toFixed(4)}, {airport.longitude.toFixed(4)}
|
||||
</div>
|
||||
<div>Control Tower: {airport.has_tower ? 'Yes' : 'No'}</div>
|
||||
<div>Beacon: {airport.has_beacon ? 'Yes' : 'No'}</div>
|
||||
{airport.latest_metar && airport.latest_metar.flight_category && (
|
||||
<>
|
||||
<Divider my='sm' />
|
||||
<div>Flight Category: {airport.latest_metar.flight_category}</div>
|
||||
</>
|
||||
<Box mb='lg'>
|
||||
{metar && metar.flight_category && (
|
||||
<Group justify='space-between' mb='md'>
|
||||
<Text style={{ color: metarColor }}>{metar.flight_category}</Text>
|
||||
<Text size='sm'>{metar.observation_time ? new Date(metar.observation_time).toLocaleString() : 'N/A'}</Text>
|
||||
</Group>
|
||||
)}
|
||||
</Group>
|
||||
<Group>
|
||||
<div>ICAO: {airport.icao}</div>
|
||||
<div>Category: {airportCategoryToText(airport.category)}</div>
|
||||
<div>
|
||||
Country / Region: {airport.iso_country}, {airport.iso_region}
|
||||
</div>
|
||||
<div>Municipality: {airport.municipality || 'N/A'}</div>
|
||||
<div>Local Code: {airport.local || 'N/A'}</div>
|
||||
<div>Elevation: {airport.elevation_ft}</div>
|
||||
<div>
|
||||
Coordinates: {airport.latitude.toFixed(4)}, {airport.longitude.toFixed(4)}
|
||||
</div>
|
||||
<div>Control Tower: {airport.has_tower ? 'Yes' : 'No'}</div>
|
||||
<div>Beacon: {airport.has_beacon ? 'Yes' : 'No'}</div>
|
||||
{metar && metar.flight_category && (
|
||||
<>
|
||||
<Divider my='sm' />
|
||||
<div>Flight Category: {metar.flight_category}</div>
|
||||
</>
|
||||
)}
|
||||
</Group>
|
||||
</Box>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Airport, AirportCategory } from '@lib/airport.types.ts';
|
||||
import { Marker, Popup } from 'react-leaflet';
|
||||
import L from 'leaflet';
|
||||
import { useRef } from 'react';
|
||||
import { getMarkerColor } from '@lib/metar.types.ts';
|
||||
|
||||
export default function AirportMarker({
|
||||
index,
|
||||
@@ -34,21 +35,6 @@ export default function AirportMarker({
|
||||
);
|
||||
}
|
||||
|
||||
function getMarkerInfo(flightCategory: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN'): [string, number] {
|
||||
switch (flightCategory) {
|
||||
case 'IFR':
|
||||
return ['#ff0100', 5];
|
||||
case 'LIFR':
|
||||
return ['#7f007f', 6];
|
||||
case 'MVFR':
|
||||
return ['#00f', 7];
|
||||
case 'VFR':
|
||||
return ['#018000', 8];
|
||||
case 'UNKN':
|
||||
return ['#696969', 4];
|
||||
}
|
||||
}
|
||||
|
||||
function createCustomIcon(airport: Airport): L.DivIcon {
|
||||
if (airport.category === AirportCategory.HELIPORT) {
|
||||
return L.divIcon({
|
||||
@@ -73,12 +59,12 @@ function createCustomIcon(airport: Airport): L.DivIcon {
|
||||
} else {
|
||||
// Default to a filled circle.
|
||||
const flightCategory = airport.latest_metar?.flight_category || 'UNKN';
|
||||
const info = getMarkerInfo(flightCategory);
|
||||
const color = getMarkerColor(flightCategory);
|
||||
if (flightCategory == 'UNKN') {
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div style="
|
||||
background-color: ${info[0]};
|
||||
background-color: ${color};
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
@@ -93,7 +79,7 @@ function createCustomIcon(airport: Airport): L.DivIcon {
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div style="
|
||||
background-color: ${info[0]};
|
||||
background-color: ${color};
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
|
||||
10
ui/src/lib/metar.ts
Normal file
10
ui/src/lib/metar.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Metar } from '@lib/metar.types.ts';
|
||||
import { getRequest } from '@lib/index.ts';
|
||||
|
||||
export async function getMetars({ icaos, force }: { icaos: string[]; force?: boolean }): Promise<Metar[]> {
|
||||
const response = await getRequest('metars', {
|
||||
icaos: icaos,
|
||||
force: force
|
||||
});
|
||||
return response?.json() || {};
|
||||
}
|
||||
@@ -3,12 +3,24 @@ export interface SkyCondition {
|
||||
cloud_base_ft_agl: number;
|
||||
}
|
||||
|
||||
export interface QualityControlFlags {
|
||||
auto: boolean;
|
||||
auto_station_without_precipitation: boolean;
|
||||
auto_station_with_precipication: boolean;
|
||||
maintenance_indicator_on: boolean;
|
||||
corrected: boolean;
|
||||
export interface PeakWind {
|
||||
degrees: number;
|
||||
speed: number;
|
||||
hour?: number;
|
||||
minute?: number;
|
||||
}
|
||||
|
||||
export interface Remarks {
|
||||
peak_wind?: PeakWind;
|
||||
auto_station_type?: string;
|
||||
maintenance_indicator_on?: boolean;
|
||||
rvr_missing?: boolean;
|
||||
precipitation_identifier_information_not_available?: boolean;
|
||||
precipitation_information_not_available?: boolean;
|
||||
freezing_rain_information_not_available?: boolean;
|
||||
thunderstorm_information_not_available?: boolean;
|
||||
visibility_at_secondary_location_not_available?: boolean;
|
||||
sky_condition_at_secondary_location_not_available?: boolean;
|
||||
}
|
||||
|
||||
export interface RunwayVisualRange {
|
||||
@@ -19,25 +31,44 @@ export interface RunwayVisualRange {
|
||||
}
|
||||
|
||||
export interface Metar {
|
||||
icao: string;
|
||||
raw_text: string;
|
||||
station_id: string;
|
||||
observation_time: string;
|
||||
temp_c: number;
|
||||
dewpoint_c: number;
|
||||
wind_dir_degrees: string;
|
||||
wind_speed_kt: number;
|
||||
wind_gust_kt: number;
|
||||
variable_wind_dir_degrees: string;
|
||||
visibility_statute_mi: string;
|
||||
flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN';
|
||||
report_modifier?: string;
|
||||
becoming_change?: boolean;
|
||||
no_significant_change?: boolean;
|
||||
temporary_change?: boolean;
|
||||
temp_c?: number;
|
||||
dew_point_c?: number;
|
||||
estimated_humidity?: number;
|
||||
wind_dir_degrees?: string;
|
||||
wind_speed_kt?: number;
|
||||
wind_gust_kt?: number;
|
||||
variable_wind_dir_degrees?: string;
|
||||
visibility_statute_mi?: string;
|
||||
runway_visual_range: RunwayVisualRange[];
|
||||
altim_in_hg: number;
|
||||
sea_level_pressure_mb: number;
|
||||
quality_control_flags: QualityControlFlags;
|
||||
altimeter_in_hg?: number;
|
||||
sea_level_pressure_mb?: number;
|
||||
remarks: Remarks;
|
||||
weather_phenomena: string[];
|
||||
sky_condition: SkyCondition[];
|
||||
flight_category: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN';
|
||||
three_hr_pressure_tendency_mb: number;
|
||||
max_t_c: number;
|
||||
min_t_c: number;
|
||||
precip_in: number;
|
||||
max_temp_c?: number;
|
||||
min_temp_c?: number;
|
||||
density_altutude?: number;
|
||||
}
|
||||
|
||||
export function getMarkerColor(flightCategory: 'VFR' | 'MVFR' | 'LIFR' | 'IFR' | 'UNKN'): string {
|
||||
switch (flightCategory) {
|
||||
case 'IFR':
|
||||
return '#ff0100';
|
||||
case 'LIFR':
|
||||
return '#7f007f';
|
||||
case 'MVFR':
|
||||
return '#00f';
|
||||
case 'VFR':
|
||||
return '#018000';
|
||||
case 'UNKN':
|
||||
return '#696969';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user