app / src /pages /Security.tsx
AZILS's picture
Upload 323 files
a21c316 verified
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Shield, Lock, FileText, Settings, Activity, RefreshCw } from 'lucide-react';
import { IpAccessLogs } from '../components/security/IpAccessLogs';
import { BlacklistManager } from '../components/security/BlacklistManager';
import { WhitelistManager } from '../components/security/WhitelistManager';
import { SecurityConfig } from '../components/security/SecurityConfig';
import { IpStatistics } from '../components/security/IpStatistics';
const Security: React.FC = () => {
const { t } = useTranslation();
const [activeTab, setActiveTab] = useState<'logs' | 'stats' | 'blacklist' | 'whitelist' | 'config'>('logs');
const [refreshKey, setRefreshKey] = useState(0);
const handleRefresh = () => {
setRefreshKey(prev => prev + 1);
};
const renderContent = () => {
switch (activeTab) {
case 'logs':
return <IpAccessLogs refreshKey={refreshKey} />;
case 'stats':
return <IpStatistics refreshKey={refreshKey} />;
case 'blacklist':
return <BlacklistManager refreshKey={refreshKey} />;
case 'whitelist':
return <WhitelistManager refreshKey={refreshKey} />;
case 'config':
return <SecurityConfig />;
default:
return <IpAccessLogs refreshKey={refreshKey} />;
}
};
const tabs = [
{ id: 'logs', label: t('security.tab_logs'), icon: FileText },
{ id: 'stats', label: t('security.tab_stats'), icon: Activity },
{ id: 'blacklist', label: t('security.tab_blacklist'), icon: Shield },
{ id: 'whitelist', label: t('security.tab_whitelist'), icon: Lock },
{ id: 'config', label: t('security.tab_config'), icon: Settings },
];
return (
<div className="h-full flex flex-col p-5 gap-4 max-w-7xl mx-auto w-full">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
<Shield className="text-blue-500" />
{t('security.title')}
</h1>
{activeTab !== 'config' && (
<button
onClick={handleRefresh}
className="btn btn-sm btn-ghost gap-2 text-gray-600 dark:text-gray-400"
title={t('security.refresh_data')}
>
<RefreshCw size={16} />
{t('security.refresh')}
</button>
)}
</div>
<div className="bg-white dark:bg-base-100 rounded-xl shadow-sm border border-gray-100 dark:border-base-200 mt-2">
<div className="flex border-b border-gray-100 dark:border-base-200">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as any)}
className={`flex items-center gap-2 px-6 py-4 text-sm font-medium transition-colors relative ${activeTab === tab.id
? 'text-blue-600 dark:text-blue-400'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
}`}
>
<tab.icon size={18} />
{tab.label}
{activeTab === tab.id && (
<div className="absolute bottom-0 left-0 right-0 h-0.5 bg-blue-600 dark:bg-blue-400" />
)}
</button>
))}
</div>
<div className="p-0">
{/* Content is rendered here, often components handle their own padding/layout */}
</div>
</div>
<div className="flex-1 overflow-hidden flex flex-col bg-white dark:bg-base-100 rounded-xl shadow-sm border border-gray-100 dark:border-base-200">
{renderContent()}
</div>
</div>
);
};
export default Security;