// ============================================ // TOKEN STATUS COMPONENT // ============================================ // Компонент для отображения статуса токена доступа // Показывает информацию о текущем токене и времени до истечения // ============================================ const TokenStatus = ({ tokenAuthManager, web3ContractManager, onShowTokenModal }) => { const [tokenInfo, setTokenInfo] = React.useState(null); const [timeLeft, setTimeLeft] = React.useState(''); const [isExpired, setIsExpired] = React.useState(false); const [isLoading, setIsLoading] = React.useState(true); const [updateInterval, setUpdateInterval] = React.useState(null); React.useEffect(() => { if (tokenAuthManager) { loadTokenStatus(); startUpdateTimer(); } return () => { if (updateInterval) { clearInterval(updateInterval); } }; }, [tokenAuthManager]); // Загрузка статуса токена const loadTokenStatus = async () => { try { setIsLoading(true); if (!tokenAuthManager || !tokenAuthManager.isAuthenticated()) { setTokenInfo(null); setTimeLeft(''); setIsExpired(false); return; } const session = tokenAuthManager.getCurrentSession(); if (!session) { setTokenInfo(null); return; } // Получаем информацию о токене const info = tokenAuthManager.getTokenInfo(); setTokenInfo(info); // Проверяем, не истек ли токен const now = Date.now(); const expiresAt = info.expiresAt; const timeRemaining = expiresAt - now; if (timeRemaining <= 0) { setIsExpired(true); setTimeLeft('Expired'); } else { setIsExpired(false); updateTimeLeft(timeRemaining); } } catch (error) { console.error('Failed to load token status:', error); setTokenInfo(null); } finally { setIsLoading(false); } }; // Запуск таймера обновления const startUpdateTimer = () => { const interval = setInterval(() => { if (tokenInfo && !isExpired) { const now = Date.now(); const expiresAt = tokenInfo.expiresAt; const timeRemaining = expiresAt - now; if (timeRemaining <= 0) { setIsExpired(true); setTimeLeft('Expired'); // Уведомляем о истечении токена handleTokenExpired(); } else { updateTimeLeft(timeRemaining); } } }, 1000); // Обновляем каждую секунду setUpdateInterval(interval); }; // Обновление оставшегося времени const updateTimeLeft = (timeRemaining) => { const days = Math.floor(timeRemaining / (24 * 60 * 60 * 1000)); const hours = Math.floor((timeRemaining % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000)); const minutes = Math.floor((timeRemaining % (60 * 60 * 1000)) / (60 * 1000)); const seconds = Math.floor((timeRemaining % (60 * 1000)) / 1000); let timeString = ''; if (days > 0) { timeString = `${days}d ${hours}h`; } else if (hours > 0) { timeString = `${hours}h ${minutes}m`; } else if (minutes > 0) { timeString = `${minutes}m ${seconds}s`; } else { timeString = `${seconds}s`; } setTimeLeft(timeString); }; // Обработка истечения токена const handleTokenExpired = () => { // Показываем уведомление showExpiredNotification(); // Можно также автоматически открыть модальное окно для покупки нового токена // if (onShowTokenModal) { // setTimeout(() => onShowTokenModal(), 2000); // } }; // Показ уведомления об истечении const showExpiredNotification = () => { // Создаем уведомление в браузере if ('Notification' in window && Notification.permission === 'granted') { new Notification('SecureBit Token Expired', { body: 'Your access token has expired. Please purchase a new one to continue.', icon: '/logo/icon-192x192.png', tag: 'token-expired' }); } // Показываем toast уведомление showToast('Token expired', 'Your access token has expired. Please purchase a new one.', 'warning'); }; // Показ toast уведомления const showToast = (title, message, type = 'info') => { // Создаем toast элемент const toast = document.createElement('div'); toast.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm ${ type === 'warning' ? 'bg-yellow-500 text-white' : type === 'error' ? 'bg-red-500 text-white' : type === 'success' ? 'bg-green-500 text-white' : 'bg-blue-500 text-white' }`; toast.innerHTML = `

${title}

${message}

`; document.body.appendChild(toast); // Автоматически удаляем через 5 секунд setTimeout(() => { if (toast.parentElement) { toast.remove(); } }, 5000); }; // Получение названия типа токена const getTokenTypeName = (type) => { return type === 'monthly' ? 'Monthly' : 'Yearly'; }; // Получение иконки типа токена const getTokenTypeIcon = (type) => { return type === 'monthly' ? 'fa-calendar-alt' : 'fa-calendar'; }; // Получение цвета для типа токена const getTokenTypeColor = (type) => { return type === 'monthly' ? 'text-blue-500' : 'text-green-500'; }; // Получение цвета для статуса const getStatusColor = () => { if (isExpired) return 'text-red-500'; if (tokenInfo && tokenInfo.timeLeft < 24 * 60 * 60 * 1000) return 'text-yellow-500'; // Меньше дня return 'text-green-500'; }; // Получение иконки статуса const getStatusIcon = () => { if (isExpired) return 'fa-times-circle'; if (tokenInfo && tokenInfo.timeLeft < 24 * 60 * 60 * 1000) return 'fa-exclamation-triangle'; return 'fa-check-circle'; }; // Если токен не загружен или не авторизован if (isLoading) { return (
Loading token...
); } if (!tokenInfo) { return ( ); } // Если токен истек if (isExpired) { return ( ); } // Отображение активного токена return (
{/* Статус токена */}
{getTokenTypeName(tokenInfo.tokenType)} Token
{timeLeft} left
{/* Информация о токене */}
ID: {tokenInfo.tokenId}
{getTokenTypeName(tokenInfo.tokenType)}
{/* Кнопка управления */}
); }; export default TokenStatus;