import { useRef, useState } from 'react';
import type { PeriodStats } from '../services/DataService';
import type { FlowStats } from '../data/arcData';
import { Sparkline } from './Sparkline';
import { ServiceStatusDots } from './ServiceStatusDots';
import { useServiceStatus } from '../hooks/useServiceStatus';
import { CATEGORY_LABELS, CATEGORY_COLORS, type TxCategory } from '../data/commentParser';
import type { Transaction } from '../data/mockData';
interface StatsPanelProps {
stats: PeriodStats | null;
loading: boolean;
periodDays: number;
source: 'live' | 'mock';
className?: string;
currentUD: number;
animationLabel?: string;
viewMode?: 'heatmap' | 'flow';
flowStats?: FlowStats | null;
focusCity?: string | null;
onClose?: () => void;
onEndpointChange?: () => void;
allTimestamps?: number[];
transactions?: Transaction[];
}
const MEDALS = ['🥇', '🥈', '🥉'];
function StatCard({ label, value, sub, delta }: { label: string; value: string; sub?: string; delta?: 'up' | 'down' | null }) {
return (
{label}
{value}
{delta === 'up' && ↑}
{delta === 'down' && ↓}
{sub &&
{sub}
}
);
}
function formatDU(g1: number, ud: number): string {
const du = g1 / ud;
if (du < 10) return `≈ ${du.toFixed(2)} DU`;
if (du < 100) return `≈ ${du.toFixed(1)} DU`;
return `≈ ${Math.round(du).toLocaleString('fr-FR')} DU`;
}
function CityRow({ city, volume, count, countryCode, accent }: {
city: string; volume: number; count: number; countryCode: string; accent?: string;
}) {
return (
{countryCode && (
{countryCode}
)}
{city}
{volume.toLocaleString('fr-FR', { maximumFractionDigits: 0 })} Ğ1
· {count}
);
}
export function StatsPanel({ stats, loading, periodDays, source, currentUD, animationLabel, viewMode = 'heatmap', flowStats, focusCity, onClose, onEndpointChange, className, allTimestamps = [], transactions = [] }: StatsPanelProps) {
const { subsquid, cesium, recheck } = useServiceStatus();
const [openCategory, setOpenCategory] = useState(null);
const periodLabel = periodDays === 1 ? '24 dernières heures' : `${periodDays} derniers jours`;
const prevStats = useRef(null);
// Calcule le delta d'une valeur par rapport au refresh précédent
function delta(current: number, prevMap: Map, key: string) {
const prev = prevMap.get(key);
if (prev === undefined) return null;
if (current > prev) return ↑;
if (current < prev) return ↓;
return null;
}
// Construit une map volume précédent par ville
const prevCityVolume = new Map(
(prevStats.current?.topCities ?? []).map((c) => [c.name, c.volume])
);
const prevVolume = prevStats.current?.totalVolume ?? null;
const prevTxCount = prevStats.current?.transactionCount ?? null;
// Mémorise les stats après le rendu
if (stats && !loading) prevStats.current = stats;
return (
);
}