95 lines
3.1 KiB
TypeScript
Executable File
95 lines
3.1 KiB
TypeScript
Executable File
import React, { useState, useEffect } from 'react';
|
||
import { Wifi, WifiOff } from 'lucide-react';
|
||
import { connectionService, type ConnectionStatus } from '../services/connectionService';
|
||
|
||
export const ConnectionIndicator: React.FC = () => {
|
||
const [status, setStatus] = useState<ConnectionStatus>(connectionService.getStatus());
|
||
const [apiBaseUrl] = useState<string>(import.meta.env.VITE_API_BASE_URL || '');
|
||
const [showIndicator, setShowIndicator] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const unsubscribe = connectionService.subscribe((newStatus) => {
|
||
setStatus(newStatus);
|
||
});
|
||
|
||
// Не показываем индикатор сразу при загрузке, даём время на проверку подключения
|
||
const timer = setTimeout(() => {
|
||
setShowIndicator(true);
|
||
}, 2000); // 2 секунды задержка
|
||
|
||
return () => {
|
||
unsubscribe();
|
||
clearTimeout(timer);
|
||
};
|
||
}, []);
|
||
|
||
// Если API не настроен, не показываем индикатор (используется только localStorage)
|
||
if (!apiBaseUrl) {
|
||
return null;
|
||
}
|
||
|
||
// Не показываем индикатор сразу при загрузке
|
||
if (!showIndicator) {
|
||
return null;
|
||
}
|
||
|
||
// На ПК показываем индикатор только если есть проблема с подключением
|
||
// На мобильных показываем всегда для информативности
|
||
const isDesktop = typeof window !== 'undefined' && window.innerWidth >= 768;
|
||
if (isDesktop && status === 'connected') {
|
||
return null;
|
||
}
|
||
|
||
const getStatusColor = () => {
|
||
switch (status) {
|
||
case 'connected':
|
||
return 'text-emerald-500';
|
||
case 'connecting':
|
||
return 'text-amber-500';
|
||
case 'disconnected':
|
||
return 'text-red-500';
|
||
default:
|
||
return 'text-slate-400';
|
||
}
|
||
};
|
||
|
||
const getStatusBg = () => {
|
||
switch (status) {
|
||
case 'connected':
|
||
return 'bg-emerald-50';
|
||
case 'connecting':
|
||
return 'bg-amber-50';
|
||
case 'disconnected':
|
||
return 'bg-red-50';
|
||
default:
|
||
return 'bg-slate-50';
|
||
}
|
||
};
|
||
|
||
const getStatusText = () => {
|
||
switch (status) {
|
||
case 'connected':
|
||
return 'Подключено';
|
||
case 'connecting':
|
||
return 'Подключение...';
|
||
case 'disconnected':
|
||
return 'Нет подключения';
|
||
default:
|
||
return 'Неизвестно';
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className={`flex items-center gap-2 px-3 py-1.5 rounded-lg border ${getStatusBg()} ${status === 'disconnected' ? 'border-red-200' : status === 'connecting' ? 'border-amber-200' : 'border-emerald-200'} transition-all ${status === 'disconnected' ? 'shadow-sm shadow-red-500/10' : ''}`}>
|
||
{status === 'disconnected' ? (
|
||
<WifiOff className={`w-4 h-4 ${getStatusColor()}`} />
|
||
) : (
|
||
<Wifi className={`w-4 h-4 ${getStatusColor()} ${status === 'connecting' ? 'animate-pulse' : ''}`} />
|
||
)}
|
||
<span className={`text-xs font-bold ${getStatusColor()} hidden sm:inline`}>
|
||
{getStatusText()}
|
||
</span>
|
||
</div>
|
||
);
|
||
};
|