metar grid changes

This commit is contained in:
2023-08-26 14:17:37 -04:00
parent d4196a24ec
commit bea8fc6895
10 changed files with 224 additions and 83 deletions

View File

@@ -1,9 +1,9 @@
import { airports } from "@/js/state";
import { getAirport } from "@/js/state";
import Link from "next/link";
export default function Page({ params }: { params: { icao: string } }) {
const airport = airports.get(params.icao);
const airport = getAirport(params.icao);
return <>
<div className="border-b border-gray-200 bg-gray-400 px-4 py-5 sm:px-6 flex justify-between">
<h3 className="text-base font-semibold leading-6 text-gray-900">{airport?.name}</h3>

View File

@@ -1,6 +1,11 @@
import React from 'react';
import RecoilRootWrapper from '@app/recoil-root-wrapper';
import '@fortawesome/fontawesome-svg-core/styles.css';
// Prevent fontawesome from adding its CSS since we did it manually above:
import { config } from '@fortawesome/fontawesome-svg-core';
config.autoAddCss = false; /* eslint-disable import/first */
import 'styles/globals.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {

View File

@@ -1,30 +1,30 @@
import React from 'react';
import { airports } from "@/js/state";
import { setAirport } from "@/js/state";
import { Airport } from "@/js/airport";
import MetarCard from '@/components/MetarCard';
import MetarGrid from '@/components/MetarGrid';
airports.set('KJYO', new Airport('Leesburg Executive Airport', 'KJYO'))
airports.set('KHEF', new Airport('Manassas Regional Airpoirt', 'KHEF'))
airports.set('KIAD', new Airport('Dulles International Airport', 'KIAD'))
airports.set('KFDK', new Airport('Frederick Municipal Airport', 'KFDK'))
airports.set('KMRB', new Airport('Eastern West Virginia Regional Airport', 'KMRB'))
airports.set('KOKV', new Airport('Winchester Regional Airport', 'KOKV'))
airports.set('KFRR', new Airport('Front Royal-Warren County Airport', 'KFRR'))
airports.set('KLUA', new Airport('Luray Caverns Airport', 'KLUA'))
airports.set('KSHD', new Airport('Shenandoah Valley Airport', 'KSHD'))
airports.set('KCHO', new Airport('Charlottesville-Albemarle Airport', 'KCHO'))
airports.set('KCJR', new Airport('Culpeper Regional Airport', 'KCJR'))
airports.set('KHWY', new Airport('Warrenton-Fauquier Airport', 'KHWY'))
airports.set('KRMN', new Airport('Stafford Regional Airport', 'KRMN'))
airports.set('KEZF', new Airport('Shannon Airport', 'KEZF'))
setAirport('KJYO', new Airport('Leesburg Executive Airport', 'KJYO'))
setAirport('KHEF', new Airport('Manassas Regional Airpoirt', 'KHEF'))
setAirport('KIAD', new Airport('Dulles International Airport', 'KIAD'))
setAirport('KFDK', new Airport('Frederick Municipal Airport', 'KFDK'))
setAirport('KMRB', new Airport('Eastern West Virginia Regional Airport', 'KMRB'))
setAirport('KOKV', new Airport('Winchester Regional Airport', 'KOKV'))
setAirport('KFRR', new Airport('Front Royal-Warren County Airport', 'KFRR'))
setAirport('KLUA', new Airport('Luray Caverns Airport', 'KLUA'))
setAirport('KSHD', new Airport('Shenandoah Valley Airport', 'KSHD'))
setAirport('KCHO', new Airport('Charlottesville-Albemarle Airport', 'KCHO'))
setAirport('KCJR', new Airport('Culpeper Regional Airport', 'KCJR'))
setAirport('KHWY', new Airport('Warrenton-Fauquier Airport', 'KHWY'))
setAirport('KRMN', new Airport('Stafford Regional Airport', 'KRMN'))
setAirport('KEZF', new Airport('Shannon Airport', 'KEZF'))
export default function Page() {
return <>
<div className="border-b border-gray-200 bg-gray-400 px-4 py-5 sm:px-6">
<h3 className="text-base font-semibold leading-6 text-gray-900">Airports</h3>
<h3 className="text-lg font-bold leading-6 text-gray-900">Airports</h3>
</div>
<div className='p-4'>
<MetarCard airports={[...airports.values()]}/>
<MetarGrid/>
</div>
</>
}

7
src/atoms/index.ts Normal file
View File

@@ -0,0 +1,7 @@
export const airportsState = atom({
key: 'airportsState',
default: [] as Airport[]
});
import { Airport } from "@/js/airport";
import { atom } from "recoil";

View File

@@ -1,46 +0,0 @@
import { Airport } from "@/js/airport";
import { Metar, getMetars } from "@/js/weather"
import Link from "next/link"
export default async function MetarCard({airports}: {airports: Airport[]}) {
const metars = await getMetars(airports);
for (let i = 0; i < airports.length; i++) {
airports[i].metar = metars[i];
}
function metarBGColor(metar: Metar | undefined) {
if (metar?.flight_category == 'VFR') {
return 'bg-emerald-600'
} else if (metar?.flight_category == 'MVFR') {
return 'bg-blue-600'
} else if (metar?.flight_category == 'IFR') {
return 'bg-red-600'
} else if (metar?.flight_category == 'LIFR') {
return 'bg-purple-600'
} else {
return 'bg-black'
}
}
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{airports.map((airport) => (
<div
key={airport.metar?.station_id}
className={`relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-4 py-2 shadow-sm focus-within:ring-2 focus-within:ring-indigo-500 focus-within:ring-offset-2 hover:border-gray-400`}
>
<div className="min-w-0 flex-1">
<Link href={`/airport/${airport.icao}`}>
<span className="absolute inset-0" aria-hidden="true" />
<p className="text-gray-900 pb-1">{airport.name} ({airport.metar?.station_id})</p>
<p className='text-sm font-medium text-gray-500'>{airport.metar?.raw_text}</p>
<div className='mt-2'>
<span className={`truncate text-sm text-white ${metarBGColor(airport.metar)} inline-block py-2 px-4 rounded-full`}>{airport.metar?.flight_category}</span>
</div>
</Link>
</div>
</div>
))}
</div>
)
}

View File

@@ -0,0 +1,73 @@
import { Airport } from "@/js/airport";
import { getAirports, setAirport } from "@/js/state";
import { Metar, getMetars } from "@/js/weather"
import Link from "next/link"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faLocationArrow } from '@fortawesome/free-solid-svg-icons'
export default async function MetarGrid() {
const airports: Airport[] = getAirports();
async function update() {
const airports: Airport[] = getAirports();
const metars = await getMetars(airports);
for (let i = 0; i < airports.length; i++) {
airports[i].metar = metars[i];
setAirport(airports[i].icao, airports[i]);
}
// setTimeout(update, 30 * 60 * 1000);
// setTimeout(update, 5000);
}
await update();
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{airports.map((airport) => (
<MetarCard airport={airport}/>
))}
</div>
);
}
function MetarCard({ airport}: { airport: Airport}) {
function metarBGColor(metar: Metar | undefined) {
if (metar?.flight_category == 'VFR') {
return 'bg-emerald-600'
} else if (metar?.flight_category == 'MVFR') {
return 'bg-blue-600'
} else if (metar?.flight_category == 'IFR') {
return 'bg-orange-600'
} else if (metar?.flight_category == 'LIFR') {
return 'bg-red-600'
} else {
return 'bg-black'
}
}
return (
<div
key={airport.metar?.station_id}
className={`relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-4 py-2 shadow-sm focus-within:ring-2 focus-within:ring-indigo-500 focus-within:ring-offset-2 hover:border-gray-400`}
>
<div className="min-w-0 flex-1">
<Link href={`/airport/${airport.icao}`}>
<span className="absolute inset-0" aria-hidden="true" />
<p className="text-gray-900 pb-1"><span className='font-semibold'>{airport.icao}</span> {airport.name}</p>
<hr/>
<p className='text-sm font-medium text-gray-500'>{airport.metar?.raw_text}</p>
<div className='mt-2'>
<span className={`truncate text-sm text-white ${metarBGColor(airport.metar)} inline-block py-2 px-4 rounded-full`}>{airport.metar?.flight_category? airport.metar?.flight_category : 'UNKN'}</span>
<span className="truncate inline-block py-2 px-2">
{airport.metar && airport.metar.wind_dir_degrees && airport.metar.wind_dir_degrees != 0?
// <FontAwesomeIcon icon={faLocationArrow} size="2xs" style={{rotate: `${-45 + airport.metar.wind_dir_degrees}deg`}}/> : <></>
<FontAwesomeIcon icon={faLocationArrow} style={{rotate: `${-45 + airport.metar.wind_dir_degrees}deg`}} className="pr-1"/>: <></>
}
{airport.metar?.wind_speed_kt} KT
</span>
</div>
</Link>
</div>
</div>
);
}

View File

@@ -1,9 +1,15 @@
// import { atom } from "recoil";
import { Airport } from "./airport";
// export const airportsState = atom({
// key: 'airportsState',
// default: [] as Airport[]
// });
const airports: Map<string, Airport> = new Map();
export const airports: Map<string, Airport> = new Map();
export function setAirport(icao: string, airport: Airport) {
airports.set(icao, airport);
}
export function getAirport(icao: string): Airport | undefined {
return airports.get(icao);
}
export function getAirports(): Airport[] {
return [...airports.values()];
}

View File

@@ -52,8 +52,8 @@ export async function getMetars(airports: Airport[]): Promise<Metar[]> {
dewpoint_c: Number(data.dewpoint_c._text),
wind_dir_degrees: Number(data.wind_dir_degrees._text),
wind_speed_kt: Number(data.wind_speed_kt._text),
visibility_statute_mi: data.visibility_statute_mi._text,
altim_in_hg: Number(data.altim_in_hg._text),
visibility_statute_mi: data.visibility_statute_mi?._text,
altim_in_hg: Number(data.altim_in_hg?._text),
sea_level_pressure_mb: data.sea_level_pressure_mb?._text,
quality_control_flags: {
auto: data.quality_control_flags?.auto?._text == 'TRUE',