"use client"; import { useEffect, useMemo, useRef } from "react"; import { AnimatePresence, motion } from "framer-motion"; import { CloudSun, Droplets, ExternalLink, Sunrise, Sunset, Wind, X } from "lucide-react"; import { DayForecastCharts } from "@/components/charts/day-forecast-charts"; import { ForecastIcon } from "@/components/forecast/forecast-icon"; import { Card } from "@/components/ui/card"; import { useI18n } from "@/lib/i18n"; import { cn } from "@/lib/utils"; import { formatForecastRainfall, formatForecastTemperature, formatForecastWind, getForecastCondition, isForecastHourPast, } from "@/lib/forecast-utils"; import type { DailyForecast, HourlyForecast } from "@/types/forecast"; function formatHour(value: string | null) { if (!value) return "—"; return value.slice(11, 16); } function getMaximumWind(hours: HourlyForecast[]) { return hours.reduce((maximum, hour) => { if (hour.windSpeed === null) return maximum; return maximum === null ? hour.windSpeed : Math.max(maximum, hour.windSpeed); }, null); } function DayMetric({ icon: Icon, label, value }: { icon: typeof Droplets; label: string; value: string }) { return (

{label}

{value}

); } export function DayForecastModal({ day, hours, locationName, onClose, }: { day: DailyForecast | null; hours: HourlyForecast[]; locationName: string; onClose: () => void; }) { const { language, locale, t } = useI18n(); const closeButtonRef = useRef(null); const maximumWind = useMemo(() => getMaximumWind(hours), [hours]); useEffect(() => { if (!day) return; const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null; const previousOverflow = document.body.style.overflow; document.body.style.overflow = "hidden"; closeButtonRef.current?.focus(); function handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") onClose(); } window.addEventListener("keydown", handleKeyDown); return () => { window.removeEventListener("keydown", handleKeyDown); document.body.style.overflow = previousOverflow; previouslyFocused?.focus(); }; }, [day, onClose]); const formattedDate = day ? new Intl.DateTimeFormat(locale, { weekday: "long", day: "numeric", month: "long", timeZone: "UTC" }).format(new Date(`${day.date}T12:00:00Z`)) : ""; return ( {day ? ( event.stopPropagation()} >

{t("forecast.dayDetails")}

{locationName}

{formattedDate}

{getForecastCondition(day.weatherCode, language)}

{formatForecastTemperature(day.temperatureMax, language)}

{formatForecastTemperature(day.temperatureMin, language)}

{t("forecast.hourlyForDay")}

    {hours.map((hour) => { const isPast = isForecastHourPast(hour.time); return (
  • {formatHour(hour.time)}

    {formatForecastTemperature(hour.temperature, language)}

    {hour.precipitationProbability === null ? "—" : `${hour.precipitationProbability}%`}

  • ); })}

{t("forecast.source")}{" "} Open-Meteo

) : null}
); }