// CoinsDisplay.tsx import { Box, Typography } from '@mui/material'; import CustomTooltip from './Notifications/CustomTooltip'; import { useEffect, useMemo, useState } from 'react'; import { fetchCoins } from '../api'; import type { SxProps, Theme } from '@mui/material/styles'; interface CoinsDisplayProps { value?: number; username?: string; size?: 'small' | 'medium' | 'large'; showTooltip?: boolean; tooltipText?: string; showIcon?: boolean; iconColor?: string; autoUpdate?: boolean; updateInterval?: number; backgroundColor?: string; textColor?: string; onClick?: () => void; disableRefreshOnClick?: boolean; sx?: SxProps; } export default function CoinsDisplay({ value: externalValue, username, size = 'medium', showTooltip = true, tooltipText = 'Попы — внутриигровая валюта, начисляемая за время игры на серверах.', showIcon = true, iconColor = '#2bff00ff', autoUpdate = false, updateInterval = 60000, backgroundColor = 'rgba(0, 0, 0, 0.2)', textColor = 'white', onClick, disableRefreshOnClick = false, sx, }: CoinsDisplayProps) { const [isLoading, setIsLoading] = useState(false); const [settingsVersion, setSettingsVersion] = useState(0); const storageKey = useMemo(() => { // ключ под конкретного пользователя return username ? `coins:${username}` : 'coins:anonymous'; }, [username]); const readCachedCoins = (): number | null => { if (typeof window === 'undefined') return null; try { const raw = localStorage.getItem(storageKey); if (!raw) return null; const parsed = Number(raw); return Number.isFinite(parsed) ? parsed : null; } catch { return null; } }; const handleClick = () => { // 1) если передали внешний обработчик — выполняем его if (onClick) onClick(); // 2) опционально оставляем обновление баланса по клику if (!disableRefreshOnClick && username) fetchCoinsData(); }; const [coins, setCoins] = useState(() => { // 1) если пришло значение извне — оно приоритетнее if (externalValue !== undefined) return externalValue; // 2) иначе пробуем localStorage const cached = readCachedCoins(); if (cached !== null) return cached; // 3) иначе 0 return 0; }); useEffect(() => { const handler = () => setSettingsVersion((v) => v + 1); window.addEventListener('settings-updated', handler as EventListener); return () => window.removeEventListener('settings-updated', handler as EventListener); }, []); const isTooltipDisabledBySettings = useMemo(() => { try { const raw = localStorage.getItem('launcher_settings'); if (!raw) return false; const s = JSON.parse(raw); return Boolean(s?.disableToolTip); } catch { return false; } }, [settingsVersion]); const tooltipEnabled = showTooltip && !isTooltipDisabledBySettings; const getSizes = () => { switch (size) { case 'small': return { containerPadding: '0.4vw 0.8vw', iconSize: '1.4vw', fontSize: '1vw', borderRadius: '2vw', gap: '0.6vw', }; case 'large': return { containerPadding: '0.4vw 1.2vw', iconSize: '2.2vw', fontSize: '1.6vw', borderRadius: '1.8vw', gap: '0.8vw', }; case 'medium': default: return { containerPadding: '0.4vw 1vw', iconSize: '2vw', fontSize: '1.4vw', borderRadius: '1.6vw', gap: '0.6vw', }; } }; const sizes = getSizes(); const formatNumber = (num: number): string => { return num.toLocaleString('ru-RU'); }; // Сохраняем актуальный баланс в localStorage при любом изменении coins useEffect(() => { if (typeof window === 'undefined') return; try { localStorage.setItem(storageKey, String(coins)); } catch { // игнорируем (private mode, quota и т.п.) } }, [coins, storageKey]); // Если пришло внешнее значение — обновляем и оно же попадёт в localStorage через эффект выше useEffect(() => { if (externalValue !== undefined) { setCoins(externalValue); } }, [externalValue]); // При смене username можно сразу подхватить кэш, чтобы не мигало при первом fetch useEffect(() => { if (externalValue !== undefined) return; // внешнее значение важнее const cached = readCachedCoins(); if (cached !== null) setCoins(cached); // eslint-disable-next-line react-hooks/exhaustive-deps }, [storageKey]); const fetchCoinsData = async () => { if (!username) return; setIsLoading(true); try { const coinsData = await fetchCoins(username); // ВАЖНО: не показываем "..." — просто меняем число, когда пришёл ответ setCoins(coinsData.coins); } catch (error) { console.error('Ошибка при получении количества монет:', error); // оставляем старое значение (из state/localStorage) } finally { setIsLoading(false); } }; useEffect(() => { if (username && autoUpdate) { fetchCoinsData(); const coinsInterval = setInterval(fetchCoinsData, updateInterval); return () => clearInterval(coinsInterval); } }, [username, autoUpdate, updateInterval]); const handleRefresh = () => { if (username) fetchCoinsData(); }; const coinsDisplay = ( {showIcon && ( P )} {formatNumber(coins)} ); if (tooltipEnabled) { return ( {coinsDisplay} ); } return coinsDisplay; }