import { useState, useEffect } from 'react'; import { Helmet } from 'react-helmet-async'; import { FiTrendingUp, FiTrendingDown, FiStar } from 'react-icons/fi'; import { type Language, t } from '../translations'; import { AreaChart, Area, ResponsiveContainer, YAxis } from 'recharts'; import { useNavigate } from 'react-router-dom'; import { slugify } from '../utils/slugify'; import { useFavorites } from '../hooks/useFavorites'; import { CircularProgress } from './CircularProgress'; import { Tooltip } from './Tooltip'; import { TbSwimming, TbSailboat } from 'react-icons/tb'; interface Lake { id: string; name: string; river: string; priority: boolean; level: number; capacity: number; storageDiff?: number; inflow: number; outflow: number; volume: number; maxVolume: number; navigationForbidden: boolean; sparkline: number[]; country?: string; area?: number; depth?: number; } const getFlagEmoji = (countryCode?: string) => { const code = countryCode || 'CZ'; const codePoints = code .toUpperCase() .split('') .map(char => 127397 + char.charCodeAt(0)); return String.fromCodePoint(...codePoints); }; const LakeCard = ({ lake, language, isFav, onToggleFav }: { lake: Lake, language: Language, isFav: boolean, onToggleFav: (id: string) => void }) => { const navigate = useNavigate(); const chartData = lake.sparkline.map((val, i) => ({ name: i, value: val })); const minVal = Math.min(...lake.sparkline); const maxVal = Math.max(...lake.sparkline); const diff = maxVal - minVal; const padding = diff === 0 ? 0.1 : diff * 0.1; // dynamic 10% padding const yDomain = [minVal - padding, maxVal + padding]; const firstVal = lake.sparkline[0] || 0; const lastVal = lake.sparkline[lake.sparkline.length - 1] || 0; const trendDiff = lastVal - firstVal; // Dynamic color based on trend direction: stable=cyan, rising=green, falling=red let trendColor = 'var(--color-cyan)'; if (trendDiff > 0.01) trendColor = 'var(--color-green)'; else if (trendDiff < -0.01) trendColor = 'var(--color-red)'; return (
navigate(`/${slugify(lake.name)}`)} style={{ cursor: 'pointer', flex: 1, padding: '1.5rem', display: 'flex', flexDirection: 'column', gap: '1.5rem', position: 'relative' }} > {/* Star / Favorite button */} {/* Flag / Country badge */} {lake.country && lake.country !== 'CZ' && ( {lake.country} )}

{getFlagEmoji(lake.country)} {lake.name} {lake.river ? `- ${lake.river}` : ''}

Water level
{lake.level} m n.m.
{lake.storageDiff !== undefined && (
= 0 ? 'var(--color-green)' : 'var(--color-red)', fontWeight: 'bold', whiteSpace: 'nowrap' }}> {lake.storageDiff > 0 ? '+' : ''}{lake.storageDiff.toFixed(2)} m
)} {lake.maxVolume > 0 && (
{lake.volume.toFixed(1)} / {lake.maxVolume.toFixed(1)} mil. m³
)}
{((lake.area !== undefined && lake.area > 0) || (lake.depth !== undefined && lake.depth > 0)) && (
{lake.area !== undefined && lake.area > 0 && ( {language === 'cs' ? 'Rozloha:' : 'Area:'} {lake.area} km² )} {lake.depth !== undefined && lake.depth > 0 && ( {language === 'cs' ? 'Hloubka:' : 'Depth:'} {lake.depth} m )}
)}
Inflow {lake.inflow} m³/s
Outflow {lake.outflow} m³/s
); }; interface Props { language: Language; windUnit?: 'kmh' | 'ms'; } const LakesOverview = ({ language }: Props) => { const [lakes, setLakes] = useState([]); const [selectedCountry, setSelectedCountry] = useState(() => sessionStorage.getItem('lakes_selectedCountry') || 'ALL'); const [sortBy, setSortBy] = useState(() => sessionStorage.getItem('lakes_sortBy') || 'name-asc'); const { isFavorite, toggleFavorite } = useFavorites(); useEffect(() => { sessionStorage.setItem('lakes_selectedCountry', selectedCountry); }, [selectedCountry]); useEffect(() => { sessionStorage.setItem('lakes_sortBy', sortBy); }, [sortBy]); useEffect(() => { const loadData = () => { fetch(`/data/lakes_index.json?t=${Date.now()}`) .then(res => res.json()) .then(data => setLakes(data.filter((l: Lake & { type?: string }) => l.type !== 'river'))) .catch(err => console.error(err)); }; loadData(); const intervalId = setInterval(loadData, 60 * 1000); // Poll every 1 minute return () => clearInterval(intervalId); }, []); const countries = Array.from(new Set(lakes.map(l => l.country || 'CZ'))).filter(Boolean).sort(); const sortLakes = (list: Lake[]) => { return [...list].sort((a, b) => { switch (sortBy) { case 'volume-desc': return (b.maxVolume || 0) - (a.maxVolume || 0); case 'area-desc': return (b.area || 0) - (a.area || 0); case 'depth-desc': return (b.depth || 0) - (a.depth || 0); case 'name-desc': return b.name.localeCompare(a.name); case 'capacity-desc': return b.capacity - a.capacity; case 'inflow-desc': return parseFloat(b.inflow as any) - parseFloat(a.inflow as any); case 'outflow-desc': return parseFloat(b.outflow as any) - parseFloat(a.outflow as any); case 'name-asc': default: return a.name.localeCompare(b.name); } }); }; // Filter based on country const countryFiltered = lakes.filter(l => selectedCountry === 'ALL' || (l.country || 'CZ') === selectedCountry); // Filter based on sorting preset requirements if needed const preFiltered = (() => { if (sortBy === 'area-desc') { return countryFiltered.filter(l => l.area !== undefined && l.area > 0); } if (sortBy === 'depth-desc') { return countryFiltered.filter(l => l.depth !== undefined && l.depth > 0); } if (sortBy === 'volume-desc') { return countryFiltered.filter(l => l.maxVolume !== undefined && l.maxVolume > 0); } return countryFiltered; })(); const sortedLakes = sortLakes(preFiltered); const isPhysicalRank = ['volume-desc', 'area-desc', 'depth-desc'].includes(sortBy); const priorityLakes = !isPhysicalRank ? sortedLakes.filter(l => l.priority) : []; const otherLakes = !isPhysicalRank ? sortedLakes.filter(l => !l.priority) : []; const rankedLakes = isPhysicalRank ? sortedLakes : []; return (
{t[language].seo.homeTitle}

{t[language].sidebar.lakes} ({lakes.length})

{t[language].seo.homeDesc}

{/* FILTER PANEL */}
{/* SORT BY FILTER (MAIN / FIRST) */}
{/* COUNTRY FILTER (SECOND) */}
{/* RENDER RANKED / SINGLE LIST */} {isPhysicalRank && rankedLakes.length > 0 && (

{sortBy === 'area-desc' && (language === 'cs' ? 'Žebříček: Největší jezera a nádrže podle rozlohy' : 'Ranking: Largest Lakes & Reservoirs by Area')} {sortBy === 'depth-desc' && (language === 'cs' ? 'Žebříček: Nejhlubší jezera a nádrže' : 'Ranking: Deepest Lakes & Reservoirs')} {sortBy === 'volume-desc' && (language === 'cs' ? 'Žebříček: Největší jezera a nádrže podle objemu' : 'Ranking: Largest Lakes & Reservoirs by Volume')} {` (${rankedLakes.length})`}

{rankedLakes.map((lake, index) => (
{/* Ranking Badge */}
{index + 1}
))}
)} {/* RENDER CZ DEFAULT SPLIT LISTS */} {!isPhysicalRank && priorityLakes.length > 0 && (

{language === 'cs' ? 'Jezera a nádrže' : 'Lakes and Reservoirs'} ({priorityLakes.length})

{priorityLakes.map(lake => )}
)} {!isPhysicalRank && otherLakes.length > 0 && (

{language === 'cs' ? 'Ostatní' : 'Other'} ({otherLakes.length})

{otherLakes.map(lake => )}
)}
); }; export default LakesOverview;