import { useState, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { banSystemApi, type BanSystemStatus, type BanSystemStats, type BanUsersListResponse, type BanUserDetailResponse, type BanPunishmentsListResponse, type BanNodesListResponse, type BanAgentsListResponse, type BanTrafficViolationsResponse, type BanSettingsResponse, type BanSettingDefinition, type BanTrafficResponse, type BanReportResponse, type BanHealthResponse, } from '../api/banSystem' // Icons const ShieldIcon = () => ( ) const UsersIcon = () => ( ) const BanIcon = () => ( ) const ServerIcon = () => ( ) const AgentIcon = () => ( ) const WarningIcon = () => ( ) const RefreshIcon = () => ( ) const ChartIcon = () => ( ) const SearchIcon = () => ( ) const SettingsIcon = () => ( ) const TrafficIcon = () => ( ) const ReportIcon = () => ( ) const HealthIcon = () => ( ) type TabType = 'dashboard' | 'users' | 'punishments' | 'nodes' | 'agents' | 'violations' | 'settings' | 'traffic' | 'reports' | 'health' interface StatCardProps { title: string value: string | number subtitle?: string icon: React.ReactNode color: 'accent' | 'success' | 'warning' | 'error' | 'info' } function StatCard({ title, value, subtitle, icon, color }: StatCardProps) { const colorClasses = { accent: 'bg-accent-500/20 text-accent-400', success: 'bg-success-500/20 text-success-400', warning: 'bg-warning-500/20 text-warning-400', error: 'bg-error-500/20 text-error-400', info: 'bg-info-500/20 text-info-400', } return (
{error}
{/* Hint */}{t('banSystem.configureHint')}
{/* Buttons */}{t('banSystem.subtitle')}
| {t('banSystem.users.email')} | {t('banSystem.users.ipCount')} | {t('banSystem.users.limit')} | {t('banSystem.users.status')} | {t('banSystem.users.bans')} | {t('common.actions')} |
|---|---|---|---|---|---|
| {user.email} | {user.unique_ip_count} | {user.limit ?? '-'} | {user.is_over_limit ? t('banSystem.users.overLimit') : t('banSystem.users.ok')} | {user.blocked_count} |
| {t('banSystem.punishments.user')} | {t('banSystem.punishments.reason')} | {t('banSystem.punishments.ipCount')} | {t('banSystem.punishments.limit')} | {t('banSystem.punishments.bannedAt')} | {t('banSystem.punishments.enableAt')} | {t('common.actions')} |
|---|---|---|---|---|---|---|
|
{p.username}
{p.user_id}
|
{p.reason || '-'} | {p.ip_count} | {p.limit} | {formatDate(p.punished_at)} | {formatDate(p.enable_at)} |
| {t('banSystem.agents.node')} | {t('banSystem.agents.status')} | {t('banSystem.agents.health')} | {t('banSystem.agents.sent')} | {t('banSystem.agents.dropped')} | {t('banSystem.agents.queue')} |
|---|---|---|---|---|---|
| {agent.node_name} | {agent.is_online ? t('banSystem.agents.online') : t('banSystem.agents.offline')} | {agent.health} | {agent.sent_total.toLocaleString()} | {agent.dropped_total.toLocaleString()} | {agent.queue_size}/{agent.queue_max} |
| {t('banSystem.violations.user')} | {t('banSystem.violations.type')} | {t('banSystem.violations.description')} | {t('banSystem.violations.detectedAt')} | {t('banSystem.violations.status')} |
|---|---|---|---|---|
|
{v.username}
{v.email || '-'}
|
{v.violation_type} | {v.description || '-'} | {formatDate(v.detected_at)} | {v.resolved ? t('banSystem.violations.resolved') : t('banSystem.violations.active')} |
| {t('banSystem.traffic.username')} | {t('banSystem.traffic.bytesTotal')} | {t('banSystem.traffic.bytesLimit')} | {t('banSystem.traffic.status')} |
|---|---|---|---|
| {user.username} | {formatBytes(user.bytes_total)} | {user.bytes_limit ? formatBytes(user.bytes_limit) : '-'} | {user.over_limit ? t('banSystem.traffic.overLimit') : t('banSystem.traffic.ok')} |
| {t('banSystem.violations.user')} | {t('banSystem.violations.type')} | {t('banSystem.violations.detectedAt')} |
|---|---|---|
| {v.username} | {v.violation_type} | {formatDate(v.detected_at)} |
| {t('banSystem.reports.username')} | {t('banSystem.reports.count')} |
|---|---|
| {v.username} | {v.count} |
| {t('banSystem.userDetail.ip')} | {t('banSystem.userDetail.country')} | {t('banSystem.userDetail.node')} | {t('banSystem.userDetail.requests')} |
|---|---|---|---|
| {ip.ip} | {ip.country_name || ip.country_code || '-'} | {ip.node || '-'} | {ip.request_count} |