75 lines
2.9 KiB
TypeScript
75 lines
2.9 KiB
TypeScript
import {
|
|
normalizeHydroStation,
|
|
normalizeSynopStation,
|
|
normalizeWarning,
|
|
} from "@/lib/weather-utils";
|
|
import type {
|
|
HydroStation,
|
|
MeteoStationPosition,
|
|
RawHydroStation,
|
|
RawMeteoStation,
|
|
RawSynopStation,
|
|
RawWarning,
|
|
SynopStation,
|
|
WeatherWarning,
|
|
WarningKind,
|
|
} from "@/types/imgw";
|
|
|
|
async function getJson<T>(path: string, signal?: AbortSignal): Promise<T> {
|
|
const response = await fetch(`/api/imgw/${path}`, { signal });
|
|
if (!response.ok) {
|
|
const details = await response.text().catch(() => "");
|
|
throw new Error(details || `IMGW API zwróciło status ${response.status}.`);
|
|
}
|
|
return response.json() as Promise<T>;
|
|
}
|
|
|
|
export async function fetchSynopStations(signal?: AbortSignal): Promise<SynopStation[]> {
|
|
const rows = await getJson<RawSynopStation[]>("synop", signal);
|
|
return rows.map(normalizeSynopStation).filter((station): station is SynopStation => station !== null);
|
|
}
|
|
|
|
export async function fetchSynopStation(id: string, signal?: AbortSignal): Promise<SynopStation> {
|
|
const row = await getJson<RawSynopStation>(`synop/id/${encodeURIComponent(id)}`, signal);
|
|
const station = normalizeSynopStation(row);
|
|
if (!station) throw new Error("IMGW zwróciło niekompletne dane stacji.");
|
|
return station;
|
|
}
|
|
|
|
export async function fetchHydroStations(signal?: AbortSignal): Promise<HydroStation[]> {
|
|
const rows = await getJson<RawHydroStation[]>("hydro", signal);
|
|
return rows.map(normalizeHydroStation).filter((station): station is HydroStation => station !== null);
|
|
}
|
|
|
|
export async function fetchMeteoStationPositions(signal?: AbortSignal): Promise<MeteoStationPosition[]> {
|
|
const rows = await getJson<RawMeteoStation[]>("meteo", signal);
|
|
return rows.flatMap((row) => {
|
|
const latitude = Number(row.lat);
|
|
const longitude = Number(row.lon);
|
|
if (!row.nazwa_stacji?.trim() || !Number.isFinite(latitude) || !Number.isFinite(longitude)) return [];
|
|
return [{ name: row.nazwa_stacji, latitude, longitude }];
|
|
});
|
|
}
|
|
|
|
async function fetchWarningsByKind(kind: WarningKind, signal?: AbortSignal): Promise<WeatherWarning[]> {
|
|
const rows = await getJson<RawWarning[]>(kind === "meteo" ? "warningsmeteo" : "warningshydro", signal);
|
|
return Array.isArray(rows) ? rows.map((warning, index) => normalizeWarning(warning, kind, index)) : [];
|
|
}
|
|
|
|
function compareWarnings(a: WeatherWarning, b: WeatherWarning) {
|
|
if (a.kind !== b.kind) return a.kind === "meteo" ? -1 : 1;
|
|
return (b.publishedAt ?? "").localeCompare(a.publishedAt ?? "");
|
|
}
|
|
|
|
export async function fetchWarnings(signal?: AbortSignal): Promise<WeatherWarning[]> {
|
|
const results = await Promise.allSettled([
|
|
fetchWarningsByKind("meteo", signal),
|
|
fetchWarningsByKind("hydro", signal),
|
|
]);
|
|
const warnings = results.flatMap((result) => result.status === "fulfilled" ? result.value : []);
|
|
if (results.every((result) => result.status === "rejected")) {
|
|
throw new Error("Nie udało się pobrać ostrzeżeń IMGW.");
|
|
}
|
|
return warnings.sort(compareWarnings);
|
|
}
|