feat: Implement Wunderground data integration, enhance dashboard weather data processing, and add future forecast modal.
This commit is contained in:
@@ -66,6 +66,25 @@ export interface CurrentConditions {
|
||||
dewpoint?: number | null;
|
||||
}
|
||||
|
||||
export interface AirportCurrentConditions {
|
||||
temp: number | null;
|
||||
obs_time: string | null;
|
||||
max_so_far?: number | null;
|
||||
max_temp_time?: string | null;
|
||||
obs_age_min?: number | null;
|
||||
report_time?: string | null;
|
||||
receipt_time?: string | null;
|
||||
obs_time_epoch?: number | null;
|
||||
wind_speed_kt?: number | null;
|
||||
wind_dir?: number | null;
|
||||
humidity?: number | null;
|
||||
cloud_desc?: string | null;
|
||||
visibility_mi?: number | null;
|
||||
wx_desc?: string | null;
|
||||
raw_metar?: string | null;
|
||||
source_label?: string | null;
|
||||
}
|
||||
|
||||
export interface NearbyStation {
|
||||
name?: string;
|
||||
icao?: string;
|
||||
@@ -271,6 +290,7 @@ export interface CityDetail {
|
||||
local_date: string;
|
||||
risk: DashboardRisk;
|
||||
current: CurrentConditions;
|
||||
airport_current?: AirportCurrentConditions;
|
||||
mgm?: MgmData;
|
||||
mgm_nearby?: NearbyStation[];
|
||||
nearby_source?: string;
|
||||
|
||||
@@ -284,6 +284,10 @@ export function getTemperatureChartData(
|
||||
? metarObservationSource
|
||||
: officialObservationSource
|
||||
: metarObservationSource;
|
||||
const airportMetarSource =
|
||||
settlementSource && observationCode === "wunderground"
|
||||
? metarObservationSource
|
||||
: [];
|
||||
const metarFallbackTag = (() => {
|
||||
const icao = String(detail.risk?.icao || "").trim().toUpperCase();
|
||||
if (!icao) return "METAR";
|
||||
@@ -314,6 +318,20 @@ export function getTemperatureChartData(
|
||||
existing == null ? temp : Math.max(Number(existing), Number(temp));
|
||||
}
|
||||
});
|
||||
const airportMetarPoints = new Array(times.length).fill(null);
|
||||
airportMetarSource.forEach((item) => {
|
||||
const parts = String(item.time || "").split(":");
|
||||
const hour = Number.parseInt(parts[0], 10);
|
||||
if (Number.isNaN(hour)) return;
|
||||
const key = `${String(hour).padStart(2, "0")}:00`;
|
||||
const index = times.indexOf(key);
|
||||
const temp = item.temp ?? null;
|
||||
if (index >= 0 && temp != null) {
|
||||
const existing = airportMetarPoints[index];
|
||||
airportMetarPoints[index] =
|
||||
existing == null ? temp : Math.max(Number(existing), Number(temp));
|
||||
}
|
||||
});
|
||||
|
||||
const mgmPoints = new Array(times.length).fill(null);
|
||||
if (detail.mgm?.temp != null && detail.mgm?.time) {
|
||||
@@ -344,6 +362,7 @@ export function getTemperatureChartData(
|
||||
const allValues = [
|
||||
...debTemps.filter((value) => value != null),
|
||||
...metarPoints.filter((value) => value != null),
|
||||
...airportMetarPoints.filter((value) => value != null),
|
||||
...mgmPoints.filter((value) => value != null),
|
||||
...mgmHourlyPoints.filter((value) => value != null),
|
||||
] as number[];
|
||||
@@ -414,6 +433,18 @@ export function getTemperatureChartData(
|
||||
.join(" -> ");
|
||||
legendParts.push(`${observationDisplayTag}: ${recentText}`);
|
||||
}
|
||||
if (airportMetarSource.length > 0) {
|
||||
const airportRecentText = [...airportMetarSource]
|
||||
.slice(-4)
|
||||
.reverse()
|
||||
.map((item) => `${item.temp}${detail.temp_symbol}@${item.time}`)
|
||||
.join(" -> ");
|
||||
legendParts.push(
|
||||
isEnglish(locale)
|
||||
? `${metarFallbackTag}: ${airportRecentText}`
|
||||
: `${metarFallbackTag}: ${airportRecentText}`,
|
||||
);
|
||||
}
|
||||
if (shouldUseMetarFallback) {
|
||||
legendParts.push(
|
||||
isEnglish(locale)
|
||||
@@ -453,6 +484,7 @@ export function getTemperatureChartData(
|
||||
|
||||
return {
|
||||
datasets: {
|
||||
airportMetarPoints,
|
||||
debFuture,
|
||||
debPast,
|
||||
hasMgmHourly,
|
||||
|
||||
Reference in New Issue
Block a user