feat: add global weather support
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s

This commit is contained in:
zv
2026-06-14 15:53:34 +02:00
parent d572c9cc53
commit 2182297adc
45 changed files with 739 additions and 212 deletions

View File

@@ -65,8 +65,12 @@ export interface DailyForecast {
export interface WeatherForecast {
latitude: number;
longitude: number;
region: WeatherRegion;
timezone: string;
hourly: HourlyForecast[];
daily: DailyForecast[];
sources: ForecastSource[];
capabilities: WeatherCapabilities;
unavailableReasons: string[];
}
import type { WeatherCapabilities, WeatherRegion } from "@/types/weather-region";

View File

@@ -23,10 +23,11 @@ export interface RawImgwHybridWeatherResponse {
}
export type CurrentWeatherCondition = "rain" | "snow" | "thunderstorm" | null;
export type ImgwCurrentWeatherCoverage = "full" | "hourly" | "precipitation-only";
export type ImgwCurrentWeatherCoverage = "full" | "hourly" | "precipitation-only" | "global-model";
export interface ImgwCurrentWeather {
export interface ImgwCurrentWeather extends WeatherSourceMetadata {
coverage: ImgwCurrentWeatherCoverage;
region: WeatherRegion;
measuredAt: string;
temperature: number | null;
feelsLike: number | null;
@@ -41,3 +42,4 @@ export interface ImgwCurrentWeather {
weatherCode: number | null;
condition: CurrentWeatherCondition;
}
import type { WeatherRegion, WeatherSourceMetadata } from "@/types/weather-region";

View File

@@ -1,3 +1,5 @@
import type { WeatherRegion } from "@/types/weather-region";
export interface LocationSearchResult {
id: number;
name: string;
@@ -5,22 +7,40 @@ export interface LocationSearchResult {
longitude: number;
province: string | null;
district: string | null;
country: string | null;
countryCode: string | null;
admin1: string | null;
admin2: string | null;
timezone: string | null;
region: WeatherRegion;
}
export interface ReverseLocationResult {
name: string;
province: string | null;
district: string | null;
country: string | null;
countryCode: string | null;
admin1: string | null;
admin2: string | null;
timezone: string | null;
region: WeatherRegion;
}
export interface SelectedLocation {
name: string;
province: string | null;
district: string | null;
country: string | null;
countryCode: string | null;
admin1: string | null;
admin2: string | null;
timezone: string | null;
region: WeatherRegion;
countyTeryt: string | null;
latitude: number;
longitude: number;
stationId: string;
stationName: string;
distanceKm: number;
stationId: string | null;
stationName: string | null;
distanceKm: number | null;
}

View File

@@ -1,6 +1,7 @@
import type { Language } from "@/lib/i18n";
import type { Province } from "@/types/province";
import type { TemperatureUnit, WindSpeedUnit } from "@/types/units";
import type { WeatherRegion } from "@/types/weather-region";
export interface PushSubscriptionKeys {
p256dh: string;
@@ -16,7 +17,8 @@ export interface BrowserPushSubscription {
export interface WarningPushSubscription {
endpoint: string;
subscription: BrowserPushSubscription;
province: Province;
province: Province | null;
region: WeatherRegion;
language: Language;
enabled: boolean;
morningBriefEnabled: boolean;
@@ -24,6 +26,7 @@ export interface WarningPushSubscription {
latitude: number | null;
longitude: number | null;
locationName: string | null;
timezone: string | null;
countyTeryt: string | null;
temperatureUnit: TemperatureUnit;
windSpeedUnit: WindSpeedUnit;

53
types/weather-region.ts Normal file
View File

@@ -0,0 +1,53 @@
export type WeatherRegion = "PL" | "GLOBAL";
export type WeatherSource = "IMGW" | "ALARO" | "OPEN_METEO";
export type WeatherSourceType = "observation" | "model" | "hybrid" | "official_warning";
export interface WeatherCapabilities {
current: boolean;
forecastHourly: boolean;
forecastDaily: boolean;
officialWarnings: boolean;
countyFiltering: boolean;
brief: boolean;
pushOfficialAlerts: boolean;
}
export interface WeatherSourceMetadata {
source: WeatherSource;
sourceLabel: string;
sourceType: WeatherSourceType;
isOfficial: boolean;
fetchedAt?: string;
generatedAt?: string;
}
export const WEATHER_CAPABILITIES: Record<WeatherRegion, WeatherCapabilities> = {
PL: {
current: true,
forecastHourly: true,
forecastDaily: true,
officialWarnings: true,
countyFiltering: true,
brief: true,
pushOfficialAlerts: true,
},
GLOBAL: {
current: true,
forecastHourly: true,
forecastDaily: true,
officialWarnings: false,
countyFiltering: false,
brief: true,
pushOfficialAlerts: false,
},
};
export function getWeatherRegionForCountryCode(countryCode?: string | null): WeatherRegion {
return countryCode?.trim().toUpperCase() === "PL" ? "PL" : "GLOBAL";
}
export function getWeatherCapabilities(region?: WeatherRegion | null) {
return WEATHER_CAPABILITIES[region ?? "PL"];
}