All files / src/components KpiCards.tsx

53.84% Statements 7/13
65.21% Branches 15/23
33.33% Functions 2/6
58.33% Lines 7/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                                        1x 3x 3x 3x   3x 3x               3x                                                                                                                                                                                          
import { FiArrowUp, FiArrowDown } from 'react-icons/fi';
import { type Language, t } from '../translations';
import { useState, useEffect } from 'react';
 
interface KpiData {
  level: number;
  inflow: number;
  outflow: number;
  outflow: number;
  volume: number;
  fullness: number;
  storageDiff?: number;
}
 
interface Props {
  data: KpiData;
  language: Language;
  lakeName?: string;
}
 
const KpiCards = ({ data, language, lakeName = 'Lipno 1' }: Props) => {
  const [showTooltip, setShowTooltip] = useState(false);
  const dict = t[language].kpi;
  const flowDiff = data.inflow - data.outflow;
 
  useEffect(() => {
    Iif (showTooltip) {
      const timer = setTimeout(() => {
        setShowTooltip(false);
      }, 3500);
      return () => clearTimeout(timer);
    }
  }, [showTooltip]);
 
  return (
    <div className="kpi-grid-container">
      {/* CARD 1: HLADINA */}
      <div className="kpi-card">
        <div style={{ fontSize: '1rem', color: 'var(--text-muted)', marginBottom: '0.5rem' }}>
          {dict.level} {lakeName}
        </div>
        <div style={{ fontSize: '2.5rem', fontWeight: 'bold', color: 'var(--color-cyan)', lineHeight: 1, marginBottom: '0.5rem' }}>
          {data.level.toFixed(2)} <span style={{ fontSize: '1rem', color: 'var(--text-muted)', fontWeight: 'normal' }}>m n. m.</span>
        </div>
        <div style={{ fontSize: '0.85rem', color: 'var(--color-green)' }}>
          (+0.02 m / 24h)
        </div>
        
        {/* Decorative Circle for Level */}
        <div style={{ position: 'absolute', right: '1.5rem', top: '1.5rem', width: '40px', height: '40px', borderRadius: '50%', border: '4px solid rgba(0, 195, 255, 0.2)', borderTopColor: 'var(--color-cyan)', transform: 'rotate(45deg)' }}></div>
      </div>
 
      {/* CARD 2: PRŮTOK */}
      <div className="kpi-card">
        <div style={{ fontSize: '1rem', color: 'var(--text-muted)', marginBottom: '0.5rem' }}>
          {dict.flow}
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', height: '100%' }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem', fontSize: '0.85rem' }}>
            <div style={{ fontSize: '0.85rem', color: 'var(--text-muted)', display: 'flex', alignItems: 'center' }}>
              <span style={{ display: 'inline-block', width: '8px', height: '8px', borderRadius: '50%', backgroundColor: '#8b5cf6', marginRight: '6px' }}></span>
              {dict.inflow}: <span style={{ fontWeight: 'bold', color: 'var(--text-main)', marginLeft: '4px' }}>{data.inflow.toFixed(1)} m³/s</span>
            </div>
            <div style={{ fontSize: '0.85rem', color: 'var(--text-muted)', marginTop: '0.25rem', display: 'flex', alignItems: 'center', gap: '0.25rem' }}>
              <span style={{ display: 'inline-block', width: '8px', height: '8px', borderRadius: '50%', backgroundColor: 'var(--color-orange)', marginRight: '2px' }}></span>
              {dict.outflow}: <span style={{ fontWeight: 'bold', color: 'var(--text-main)' }}>{data.outflow.toFixed(1)} m³/s</span>
              {flowDiff > 0 ? <FiArrowUp color="var(--color-green)" /> : flowDiff < 0 ? <FiArrowDown color="var(--color-red)" /> : null}
            </div>
          </div>
          
          {/* Flow Circle */}
          <div style={{ width: '40px', height: '40px', borderRadius: '50%', border: '4px solid rgba(0, 195, 255, 0.2)', borderTopColor: 'var(--color-cyan)', borderRightColor: 'var(--color-cyan)', display: 'flex', alignItems: 'center', justifyContent: 'center', transform: 'rotate(-45deg)' }}>
            <span style={{ fontSize: '0.65rem', transform: 'rotate(45deg)', color: 'var(--text-main)', fontWeight: 'bold' }}>
              <div style={{ lineHeight: 1 }}>{data.outflow.toFixed(1)}</div>
              <div style={{ fontSize: '0.45rem', opacity: 0.7 }}>m³/s</div>
            </span>
          </div>
        </div>
      </div>
 
      {/* CARD 3: NAPLNĚNOST */}
      <div className="kpi-card">
        <div style={{ fontSize: '1rem', color: 'var(--text-muted)', marginBottom: '0.5rem', display: 'flex', alignItems: 'center', gap: '0.4rem', position: 'relative' }}>
          {dict.fullness}
          <span 
            onClick={() => setShowTooltip(!showTooltip)}
            style={{ cursor: 'pointer', fontSize: '0.85rem', opacity: 0.6, padding: '0 4px' }}
          >
            ⓘ
          </span>
          {showTooltip && (
            <div 
              onClick={() => setShowTooltip(false)}
              style={{
                position: 'absolute',
                bottom: '100%',
                left: '50%',
                transform: 'translateX(-50%)',
                marginBottom: '8px',
                backgroundColor: 'var(--bg-card)',
                border: '1px solid var(--border-color)',
                padding: '0.75rem',
                borderRadius: '8px',
                width: '250px',
                zIndex: 100,
                boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
                color: 'var(--text-main)',
                fontSize: '0.85rem',
                lineHeight: 1.4,
                cursor: 'pointer'
              }}>
              {language === 'cs' ? "Rozdíl mezi aktuální hladinou a hladinou zásobního prostoru (důležité pro jachtaře a rekreaci)." : "Difference between current water level and storage space level (important for sailing and recreation)."}
            </div>
          )}
        </div>
        <div style={{ fontSize: '2rem', fontWeight: 'bold', lineHeight: 1, marginBottom: '0.5rem', color: data.storageDiff && data.storageDiff < 0 ? 'var(--color-red)' : 'var(--color-cyan)' }}>
          {data.storageDiff !== undefined && data.storageDiff !== 0 ? (data.storageDiff > 0 ? `+${data.storageDiff.toFixed(2)} m` : `${data.storageDiff.toFixed(2)} m`) : (data.fullness > 0 ? `${data.fullness.toFixed(1)}%` : 'N/A')}
        </div>
        <div style={{ fontSize: '0.85rem', color: 'var(--text-muted)' }}>
          {dict.volume}: {data.volume.toFixed(1)} mil. m³
        </div>
      </div>
    </div>
  );
};
 
export default KpiCards;