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';
interface Lake {
id: string;
name: string;
river: string;
priority: boolean;
level: number;
capacity: number;
storageDiff?: number;
inflow: number;
outflow: number;
volume: number;
sparkline: number[];
}
interface Props {
language: Language;
}
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;
// Enforce a minimum visual span of 0.5 meters so tiny fluctuations don't look like mountains
const padding = diff < 0.5 ? (0.5 - diff) / 2 : 0;
const yDomain = [minVal - padding, maxVal + padding];
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 */}
{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' }}>
{lake.storageDiff > 0 ? '+' : ''}{lake.storageDiff.toFixed(2)} m
)}
Inflow {lake.inflow} m³/s
Outflow {lake.outflow} m³/s
);
};
const SmallLakeCard = ({ lake, isFav, onToggleFav }: { lake: Lake, isFav: boolean, onToggleFav: (id: string) => void }) => {
const navigate = useNavigate();
return (
navigate(`/${slugify(lake.name)}`)}
style={{ cursor: 'pointer', padding: '1rem', display: 'flex', flexDirection: 'column', gap: '0.5rem', position: 'relative' }}
>
{/* Star button */}
{lake.name}
{lake.level} m n.m.
= 80 ? 'var(--color-green)' : lake.capacity < 40 ? 'var(--color-red)' : 'var(--text-muted)', fontWeight: 600 }}>
{lake.capacity > 0 ? `${lake.capacity}%` : 'N/A'}
{lake.storageDiff !== undefined && (
= 0 ? 'var(--color-green)' : 'var(--color-red)', marginLeft: '4px' }}>
({lake.storageDiff > 0 ? '+' : ''}{lake.storageDiff.toFixed(2)} m)
)}
);
};
const LakesOverview = ({ language }: Props) => {
const [lakes, setLakes] = useState([]);
const { isFavorite, toggleFavorite, favorites } = useFavorites();
useEffect(() => {
const loadData = () => {
fetch(`/data/lakes_index.json?t=${Date.now()}`)
.then(res => res.json())
.then(data => setLakes(data))
.catch(err => console.error(err));
};
loadData();
const intervalId = setInterval(loadData, 60 * 1000); // Poll every 1 minute
return () => clearInterval(intervalId);
}, []);
const favoriteLakes = lakes.filter(l => isFavorite(l.id));
const priorityLakes = lakes.filter(l => l.priority && !isFavorite(l.id));
const otherLakes = lakes.filter(l => !l.priority && !isFavorite(l.id));
otherLakes.sort((a, b) => a.name.localeCompare(b.name));
return (
{t[language].seo.homeTitle}
{t[language].sidebar.lakes} ({lakes.length})
{t[language].seo.homeDesc}
{/* Favorites section */}
{favoriteLakes.length > 0 && (
{language === 'cs' ? 'Oblíbená' : 'Favorites'} ({favoriteLakes.length})
{favoriteLakes.map(lake => (
))}
)}
{priorityLakes.length > 0 && (
{language === 'cs' ? 'Jezera a nádrže' : 'Lakes and Reservoirs'}
{priorityLakes.map(lake => )}
)}
);
};
export default LakesOverview;