feat: add weather unit preferences
Some checks failed
CI / Lint, test, typecheck and build (push) Has been cancelled

This commit is contained in:
zv
2026-07-04 20:16:11 +02:00
parent ab6b7b414f
commit 91acdb39b8
27 changed files with 623 additions and 76 deletions

View File

@@ -11,13 +11,19 @@ import type {
import { translate, type Language } from "@/lib/i18n";
import { getProvinceFromTeryt, normalizeProvinceName } from "@/lib/provinces";
import type { CurrentWeatherCondition } from "@/types/imgw-current";
import type { TemperatureUnit, WindSpeedUnit } from "@/types/units";
import type { DistanceUnit, PrecipitationUnit, PressureUnit, TemperatureUnit, WindSpeedUnit } from "@/types/units";
const locales: Record<Language, string> = { pl: "pl-PL", en: "en-GB" };
export const DEFAULT_TEMPERATURE_UNIT: TemperatureUnit = "c";
export const TEMPERATURE_UNITS: TemperatureUnit[] = ["c", "f"];
export const DEFAULT_WIND_SPEED_UNIT: WindSpeedUnit = "kmh";
export const WIND_SPEED_UNITS: WindSpeedUnit[] = ["ms", "kmh", "mph"];
export const WIND_SPEED_UNITS: WindSpeedUnit[] = ["ms", "kmh", "mph", "kt", "bft"];
export const DEFAULT_PRECIPITATION_UNIT: PrecipitationUnit = "mm";
export const PRECIPITATION_UNITS: PrecipitationUnit[] = ["mm", "cm", "in"];
export const DEFAULT_PRESSURE_UNIT: PressureUnit = "hpa";
export const PRESSURE_UNITS: PressureUnit[] = ["hpa", "kpa", "inhg", "mmhg"];
export const DEFAULT_DISTANCE_UNIT: DistanceUnit = "km";
export const DISTANCE_UNITS: DistanceUnit[] = ["km", "mi"];
const temperatureUnitLabels: Record<TemperatureUnit, string> = {
c: "°C",
@@ -28,6 +34,26 @@ const windSpeedUnitLabels: Record<WindSpeedUnit, string> = {
ms: "m/s",
kmh: "km/h",
mph: "mph",
kt: "kt",
bft: "Bft",
};
const precipitationUnitLabels: Record<PrecipitationUnit, string> = {
mm: "mm",
cm: "cm",
in: "in",
};
const pressureUnitLabels: Record<PressureUnit, string> = {
hpa: "hPa",
kpa: "kPa",
inhg: "inHg",
mmhg: "mm Hg",
};
const distanceUnitLabels: Record<DistanceUnit, string> = {
km: "km",
mi: "mi",
};
export function toNumber(value: unknown): number | null {
@@ -152,10 +178,6 @@ export function formatTemperature(
: formatTemperatureValue(convertTemperature(value, unit), language, unit);
}
export function formatPressure(value: number | null, language: Language = "pl") {
return value === null ? translate(language, "common.noData") : `${value.toFixed(1)} hPa`;
}
export function formatHumidity(value: number | null, language: Language = "pl") {
return value === null ? translate(language, "common.noData") : `${Math.round(value)}%`;
}
@@ -168,18 +190,60 @@ export function getWindSpeedUnitLabel(unit: WindSpeedUnit) {
return windSpeedUnitLabels[unit];
}
export function isPrecipitationUnit(value: unknown): value is PrecipitationUnit {
return typeof value === "string" && PRECIPITATION_UNITS.includes(value as PrecipitationUnit);
}
export function getPrecipitationUnitLabel(unit: PrecipitationUnit) {
return precipitationUnitLabels[unit];
}
export function isPressureUnit(value: unknown): value is PressureUnit {
return typeof value === "string" && PRESSURE_UNITS.includes(value as PressureUnit);
}
export function getPressureUnitLabel(unit: PressureUnit) {
return pressureUnitLabels[unit];
}
export function isDistanceUnit(value: unknown): value is DistanceUnit {
return typeof value === "string" && DISTANCE_UNITS.includes(value as DistanceUnit);
}
export function getDistanceUnitLabel(unit: DistanceUnit) {
return distanceUnitLabels[unit];
}
export function convertWindSpeed(speed: number, unit: WindSpeedUnit) {
if (unit === "kmh") return speed * 3.6;
if (unit === "mph") return speed * 2.2369362921;
if (unit === "kt") return speed * 1.9438444924;
return speed;
}
export function convertWindSpeedToBeaufort(speed: number) {
if (speed < 0.3) return 0;
if (speed < 1.6) return 1;
if (speed < 3.4) return 2;
if (speed < 5.5) return 3;
if (speed < 8) return 4;
if (speed < 10.8) return 5;
if (speed < 13.9) return 6;
if (speed < 17.2) return 7;
if (speed < 20.8) return 8;
if (speed < 24.5) return 9;
if (speed < 28.5) return 10;
if (speed < 32.7) return 11;
return 12;
}
export function formatWindSpeed(
speed: number | null,
language: Language = "pl",
unit: WindSpeedUnit = DEFAULT_WIND_SPEED_UNIT,
) {
if (speed === null) return translate(language, "common.noData");
if (unit === "bft") return `${convertWindSpeedToBeaufort(speed)} ${getWindSpeedUnitLabel(unit)}`;
const convertedSpeed = convertWindSpeed(speed, unit);
const digits = unit === "ms" ? 1 : 0;
const formattedSpeed = new Intl.NumberFormat(locales[language], {
@@ -200,8 +264,73 @@ export function formatWind(
return `${formatWindSpeed(speed, language, unit)}${directionLabel}`;
}
export function formatRainfall(value: number | null, language: Language = "pl") {
return value === null ? translate(language, "common.noData") : `${value.toFixed(value < 1 ? 2 : 1)} mm`;
export function formatRainfall(
value: number | null,
language: Language = "pl",
unit: PrecipitationUnit = DEFAULT_PRECIPITATION_UNIT,
) {
return formatPrecipitation(value, language, unit);
}
export function convertPrecipitation(value: number, unit: PrecipitationUnit) {
if (unit === "cm") return value / 10;
if (unit === "in") return value / 25.4;
return value;
}
export function formatPrecipitation(
value: number | null,
language: Language = "pl",
unit: PrecipitationUnit = DEFAULT_PRECIPITATION_UNIT,
) {
if (value === null) return translate(language, "common.noData");
const convertedValue = convertPrecipitation(value, unit);
const digits = unit === "mm" ? (convertedValue < 1 ? 2 : 1) : unit === "cm" ? 2 : 2;
const formattedValue = new Intl.NumberFormat(locales[language], {
minimumFractionDigits: unit === "in" ? 2 : 0,
maximumFractionDigits: digits,
}).format(convertedValue);
return `${formattedValue} ${getPrecipitationUnitLabel(unit)}`;
}
export function convertPressure(value: number, unit: PressureUnit) {
if (unit === "kpa") return value / 10;
if (unit === "inhg") return value * 0.0295299830714;
if (unit === "mmhg") return value * 0.750061683;
return value;
}
export function formatPressure(
value: number | null,
language: Language = "pl",
unit: PressureUnit = DEFAULT_PRESSURE_UNIT,
) {
if (value === null) return translate(language, "common.noData");
const convertedValue = convertPressure(value, unit);
const digits = unit === "inhg" ? 2 : unit === "kpa" ? 1 : unit === "mmhg" ? 0 : 1;
const formattedValue = new Intl.NumberFormat(locales[language], {
minimumFractionDigits: unit === "inhg" ? 2 : 0,
maximumFractionDigits: digits,
}).format(convertedValue);
return `${formattedValue} ${getPressureUnitLabel(unit)}`;
}
export function convertDistance(value: number, unit: DistanceUnit) {
if (unit === "mi") return value * 0.621371;
return value;
}
export function formatDistance(
value: number | null,
language: Language = "pl",
unit: DistanceUnit = DEFAULT_DISTANCE_UNIT,
) {
if (value === null) return translate(language, "common.noData");
const convertedValue = convertDistance(value, unit);
const formattedValue = new Intl.NumberFormat(locales[language], {
maximumFractionDigits: convertedValue < 10 ? 1 : 0,
}).format(convertedValue);
return `${formattedValue} ${getDistanceUnitLabel(unit)}`;
}
export function formatWaterLevel(value: number | null, language: Language = "pl") {