139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import { Box, Drawer, Group, Tabs, TabsList, Text, Tooltip } 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';
|
|
import { useMediaQuery } from '@mantine/hooks';
|
|
|
|
export default function AirportDrawer({
|
|
airport,
|
|
setAirport
|
|
}: {
|
|
airport: Airport | null;
|
|
setAirport: (airport: Airport | null) => void;
|
|
}) {
|
|
const [metar, setMetar] = useState<Metar | undefined>(undefined);
|
|
const isMobile = useMediaQuery('(max-width: 768px)');
|
|
|
|
useEffect(() => {
|
|
if (!airport) return;
|
|
function updateMetar() {
|
|
if (!airport) return;
|
|
console.log(airport.icao);
|
|
getMetars({ icaos: [airport.icao] }).then((m) => {
|
|
if (m.length > 0) {
|
|
setMetar(m[0]);
|
|
} else {
|
|
setMetar(undefined);
|
|
}
|
|
});
|
|
}
|
|
|
|
updateMetar();
|
|
|
|
const interval = setInterval(updateMetar, 60000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, [airport]);
|
|
|
|
if (!airport) {
|
|
return null;
|
|
}
|
|
|
|
const metarColor = getMarkerColor(metar?.flight_category || 'UNKN');
|
|
|
|
return (
|
|
<Drawer
|
|
opened={true}
|
|
onClose={() => setAirport(null)}
|
|
title={airport.name}
|
|
withinPortal
|
|
zIndex={1000}
|
|
styles={{ root: { padding: 0, margin: 0, width: 0, height: 0 } }}
|
|
padding='md'
|
|
size={isMobile ? '100%' : 'md'}
|
|
position='left'
|
|
withOverlay={false}
|
|
closeOnClickOutside={false}
|
|
>
|
|
<Box mb='lg'>
|
|
{metar && metar.flight_category && (
|
|
<Group
|
|
justify='space-between'
|
|
mb='md'
|
|
style={{
|
|
backgroundColor: '#272f38',
|
|
borderTop: '1px solid #1a242f',
|
|
borderBottom: '1px solid #1a242f',
|
|
padding: '10px'
|
|
}}
|
|
>
|
|
<Text style={{ color: metarColor }}>{metar.flight_category}</Text>
|
|
<Tooltip zIndex={1001} label={new Date(metar.observation_time).toLocaleString()}>
|
|
<TimeSince date={metar.observation_time} />
|
|
</Tooltip>
|
|
</Group>
|
|
)}
|
|
<Tabs variant={'outline'} defaultValue={'info'}>
|
|
<TabsList grow>
|
|
<Tabs.Tab value={'info'}>Info</Tabs.Tab>
|
|
<Tabs.Tab value={'weather'}>Weather</Tabs.Tab>
|
|
</TabsList>
|
|
<Tabs.Panel value={'info'}><AirportInfo airport={airport}/></Tabs.Panel>
|
|
{airport.latest_metar && (
|
|
<Tabs.Panel value={'weather'}><WeatherInfo metar={airport.latest_metar} /></Tabs.Panel>
|
|
)}
|
|
</Tabs>
|
|
</Box>
|
|
</Drawer>
|
|
);
|
|
}
|
|
|
|
function AirportInfo({ airport }: { airport: Airport }) {
|
|
return (<div>
|
|
<Text>ICAO: {airport.icao}</Text>
|
|
<Text>Category: {airportCategoryToText(airport.category)}</Text>
|
|
</div>);
|
|
}
|
|
|
|
function WeatherInfo({ metar }: { metar: Metar }) {
|
|
return <>{metar.raw_text}</>
|
|
}
|
|
|
|
function airportCategoryToText(category: AirportCategory): string {
|
|
switch (category) {
|
|
case AirportCategory.SMALL:
|
|
return 'Small';
|
|
case AirportCategory.MEDIUM:
|
|
return 'Medium';
|
|
case AirportCategory.LARGE:
|
|
return 'Large';
|
|
case AirportCategory.HELIPORT:
|
|
return 'Helipad';
|
|
case AirportCategory.CLOSED:
|
|
return 'Closed';
|
|
case AirportCategory.SEAPLANE:
|
|
return 'Seaplane Base';
|
|
case AirportCategory.BALLOONPORT:
|
|
return 'Balloon Port';
|
|
default:
|
|
return 'Unknown';
|
|
}
|
|
}
|
|
|
|
function TimeSince({ date }: { date: string }) {
|
|
const inputDate = new Date(date);
|
|
// @ts-expect-error doing arithmetic with dates
|
|
const seconds = Math.floor((new Date() - inputDate) / 1000);
|
|
|
|
if (seconds < 60) {
|
|
const content = seconds + (seconds === 1 ? " second ago" : " seconds ago");
|
|
return <Text>{content}</Text>;
|
|
} else {
|
|
const minutes = Math.floor(seconds / 60);
|
|
const content = minutes + (minutes === 1 ? " minute ago" : " minutes ago");
|
|
// If more than 60 minutes have passed, set the text color to yellow
|
|
return <Text style={{ color: minutes >= 60 ? '#fca903' : undefined }}>{content}</Text>;
|
|
}
|
|
}
|