Files
Frontend/src/pages/home.page.tsx
T
nikitaa_ts 6367cdae56
CI / build (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
fix: home
2026-06-13 22:39:30 +03:00

724 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ThemeToggle } from "@/modules/theme-changer/ui/Theme.toggle";
import { useNavigate } from "react-router-dom";
import { useAuth } from "@/modules/auth/hooks/useAuth";
import { authService } from "@/modules/auth/api/auth.service";
import {
Shield,
Users,
Bot,
Activity,
LogOut,
ChevronRight,
Zap,
Lock,
Cloud,
TrendingUp,
Bell,
Server,
Sparkles,
AlertCircle,
CheckCircle,
Clock,
LogIn,
UserPlus,
} from "lucide-react";
export const HomePage = () => {
const navigate = useNavigate();
const { logout } = useAuth();
const isAuthenticated = authService.isAuthenticated();
const organization = authService.getCurrentOrganization();
const authStorage = localStorage.getItem("auth-storage");
const user = authStorage ? JSON.parse(authStorage).state?.user : null;
const stats = [
{ label: "Активные агенты", value: "12", change: "+2", icon: Server },
{ label: "Заблокировано IP", value: "1,284", change: "+128", icon: Shield },
{ label: "Активных правил", value: "47", change: "+5", icon: Lock },
{
label: "Атак предотвращено",
value: "3,721",
change: "+342",
icon: TrendingUp,
},
];
const recentActivities = [
{
id: 1,
type: "attack",
message: "Обнаружена brute-force атака с IP 192.168.1.45",
time: "2 минуты назад",
severity: "high",
},
{
id: 2,
type: "rule",
message: "Новое правило фильтрации добавлено администратором",
time: "15 минут назад",
severity: "info",
},
{
id: 3,
type: "agent",
message: "Агент на сервере web-01 успешно обновлен",
time: "1 час назад",
severity: "success",
},
{
id: 4,
type: "ai",
message: "AI предложил новые правила для обнаружения ботов",
time: "3 часа назад",
severity: "info",
},
];
const features = [
{
title: "Централизованное управление",
description: "Управляйте всеми IPS агентами из единого интерфейса",
icon: Server,
color: "#6366f1",
},
{
title: "AI Аналитика",
description: "Искусственный интеллект помогает находить сложные атаки",
icon: Bot,
color: "#8b5cf6",
},
{
title: "Мгновенная блокировка",
description: "Автоматическая блокировка IP при обнаружении угроз",
icon: Zap,
color: "#f59e0b",
},
{
title: "Безопасность данных",
description: "LLM не получает доступ к чувствительным логам",
icon: Lock,
color: "#22c55e",
},
];
const quickActions = isAuthenticated
? [
{
name: "IPS Агенты",
icon: Server,
path: "/agents",
description: "Управление агентами",
color: "#6366f1",
},
{
name: "Правила",
icon: Shield,
path: "/rules",
description: "Правила фильтрации",
color: "#22c55e",
},
{
name: "AI Аналитика",
icon: Bot,
path: "/ai-analytics",
description: "Анализ логов",
color: "#8b5cf6",
},
{
name: "Команда",
icon: Users,
path: "/organization",
description: "Управление доступом",
color: "#f59e0b",
},
]
: [];
const getSeverityStyles = (severity: string) => {
switch (severity) {
case "high":
return {
bg: "#ef444410",
border: "#ef4444",
icon: AlertCircle,
text: "#ef4444",
};
case "success":
return {
bg: "#22c55e10",
border: "#22c55e",
icon: CheckCircle,
text: "#22c55e",
};
default:
return {
bg: "#6366f110",
border: "#6366f1",
icon: Sparkles,
text: "#6366f1",
};
}
};
return (
<div
style={{ backgroundColor: "var(--bg-primary)" }}
className="min-h-screen transition-theme"
>
{/* Header */}
<header
className="sticky top-0 z-50 border-b transition-theme backdrop-blur-sm"
style={{
backgroundColor: "var(--bg-primary)",
borderColor: "var(--border)",
}}
>
<div className="container mx-auto px-6 py-4">
<div className="flex justify-between items-center">
{/* Logo */}
<div className="flex items-center gap-3">
<div
className="w-10 h-10 rounded-xl flex items-center justify-center"
style={{ backgroundColor: "var(--accent)" }}
>
<Shield className="w-6 h-6 text-white" />
</div>
<div>
<h1
className="text-xl font-bold"
style={{ color: "var(--text-primary)" }}
>
IPS Manager
</h1>
{organization && (
<p className="text-xs" style={{ color: "var(--text-muted)" }}>
{organization.name}
</p>
)}
</div>
</div>
{/* Right section */}
<div className="flex items-center gap-4">
{isAuthenticated ? (
<>
<button
className="relative p-2 rounded-lg transition-all hover:scale-105"
style={{ backgroundColor: "var(--bg-secondary)" }}
>
<Bell
className="w-5 h-5"
style={{ color: "var(--text-secondary)" }}
/>
<span
className="absolute top-1 right-1 w-2 h-2 rounded-full"
style={{ backgroundColor: "#ef4444" }}
></span>
</button>
<ThemeToggle />
<div className="flex items-center gap-3">
<div
className="w-10 h-10 rounded-full flex items-center justify-center font-semibold text-white"
style={{ backgroundColor: "var(--accent)" }}
>
{user?.first_name?.[0]}
{user?.last_name?.[0]}
</div>
<div className="hidden md:block">
<p
className="text-sm font-medium"
style={{ color: "var(--text-primary)" }}
>
{user?.first_name} {user?.last_name}
</p>
<p
className="text-xs"
style={{ color: "var(--text-muted)" }}
>
Администратор
</p>
</div>
</div>
<button
onClick={logout}
className="p-2 rounded-lg transition-all hover:scale-105"
style={{ backgroundColor: "#ef4444" }}
>
<LogOut className="w-5 h-5 text-white" />
</button>
</>
) : (
<>
<ThemeToggle />
<button
onClick={() => navigate("/auth")}
className="px-4 py-2 rounded-lg font-medium transition-all flex items-center gap-2 hover:scale-105"
style={{
backgroundColor: "var(--bg-secondary)",
color: "var(--text-primary)",
border: `1px solid var(--border)`,
}}
>
<LogIn className="w-4 h-4" />
Войти
</button>
<button
onClick={() => navigate("/auth")}
className="px-4 py-2 rounded-lg font-medium transition-all flex items-center gap-2 hover:scale-105"
style={{
backgroundColor: "var(--accent)",
color: "white",
}}
>
<UserPlus className="w-4 h-4" />
Регистрация
</button>
</>
)}
</div>
</div>
</div>
</header>
<main className="container mx-auto px-6 py-8">
{/* Hero Section */}
<div
className="rounded-2xl p-8 mb-8 text-white relative overflow-hidden"
style={{
background: "linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)",
}}
>
<div className="relative z-10">
<div className="flex justify-between items-start">
<div>
<h2 className="text-3xl font-bold mb-2">
{isAuthenticated
? `Добро пожаловать, ${user?.first_name || "Администратор"}!`
: "Добро пожаловать в IPS Manager"}
</h2>
<p className="text-white/80 text-lg">
{isAuthenticated
? "Система IPS мониторинга и защиты"
: "Современная платформа для централизованного управления IPS агентами"}
</p>
{!isAuthenticated && (
<div className="flex gap-4 mt-6">
<button
onClick={() => navigate("/auth")}
className="px-6 py-2 rounded-lg font-medium bg-white text-indigo-600 transition-all hover:scale-105 hover:shadow-lg"
>
Начать работу
</button>
<button className="px-6 py-2 rounded-lg font-medium border border-white/30 transition-all hover:bg-white/10">
Узнать больше
</button>
</div>
)}
{isAuthenticated && (
<div className="flex items-center gap-2 mt-4">
<Zap className="w-5 h-5" />
<span className="text-white/90">
Все системы работают стабильно
</span>
</div>
)}
</div>
<div className="hidden lg:block opacity-20">
<Cloud className="w-32 h-32" />
</div>
</div>
</div>
</div>
{/* Stats Grid - только для авторизованных */}
{isAuthenticated && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
{stats.map((stat, index) => {
const Icon = stat.icon;
return (
<div
key={index}
className="rounded-2xl p-6 transition-all hover:scale-105 hover:shadow-xl"
style={{
backgroundColor: "var(--card-bg)",
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<div className="flex justify-between items-start mb-4">
<div
className="w-12 h-12 rounded-xl flex items-center justify-center bg-opacity-20"
style={{
backgroundColor: `${index === 0 ? "#6366f1" : index === 1 ? "#ef4444" : index === 2 ? "#22c55e" : "#f59e0b"}20`,
}}
>
<Icon
className="w-6 h-6"
style={{
color:
index === 0
? "#6366f1"
: index === 1
? "#ef4444"
: index === 2
? "#22c55e"
: "#f59e0b",
}}
/>
</div>
<span
className="text-sm font-medium"
style={{ color: "#22c55e" }}
>
{stat.change}
</span>
</div>
<h3
className="text-2xl font-bold mb-1"
style={{ color: "var(--text-primary)" }}
>
{stat.value}
</h3>
<p
className="text-sm"
style={{ color: "var(--text-secondary)" }}
>
{stat.label}
</p>
</div>
);
})}
</div>
)}
{/* Features Section - для всех */}
<div className="mb-8">
<div className="text-center mb-8">
<h2
className="text-2xl font-bold mb-2"
style={{ color: "var(--text-primary)" }}
>
Ключевые возможности
</h2>
<p className="text-sm" style={{ color: "var(--text-secondary)" }}>
Всё необходимое для защиты вашей инфраструктуры
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{features.map((feature, index) => {
const Icon = feature.icon;
return (
<div
key={index}
className="rounded-2xl p-6 transition-all hover:scale-105 hover:shadow-xl text-center"
style={{
backgroundColor: "var(--card-bg)",
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<div
className="w-14 h-14 rounded-xl flex items-center justify-center mx-auto mb-4"
style={{ backgroundColor: `${feature.color}20` }}
>
<Icon
className="w-7 h-7"
style={{ color: feature.color }}
/>
</div>
<h3
className="font-bold mb-2"
style={{ color: "var(--text-primary)" }}
>
{feature.title}
</h3>
<p
className="text-sm"
style={{ color: "var(--text-secondary)" }}
>
{feature.description}
</p>
</div>
);
})}
</div>
</div>
{isAuthenticated ? (
<>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Quick Actions */}
<div className="lg:col-span-2">
<div
className="rounded-2xl p-6"
style={{
backgroundColor: "var(--card-bg)",
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<h3
className="text-xl font-bold mb-6"
style={{ color: "var(--text-primary)" }}
>
Быстрый доступ
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{quickActions.map((action, index) => {
const Icon = action.icon;
return (
<button
key={index}
onClick={() => navigate(action.path)}
className="group p-4 rounded-xl text-left transition-all hover:scale-[1.02]"
style={{
backgroundColor: "var(--bg-secondary)",
border: `1px solid var(--border)`,
}}
>
<div className="flex items-start justify-between">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center mb-3 transition-all group-hover:scale-110"
style={{ backgroundColor: `${action.color}20` }}
>
<Icon
className="w-5 h-5"
style={{ color: action.color }}
/>
</div>
<ChevronRight
className="w-5 h-5 opacity-0 group-hover:opacity-100 transition-all"
style={{ color: "var(--text-muted)" }}
/>
</div>
<h4
className="font-semibold mb-1"
style={{ color: "var(--text-primary)" }}
>
{action.name}
</h4>
<p
className="text-sm"
style={{ color: "var(--text-secondary)" }}
>
{action.description}
</p>
</button>
);
})}
</div>
</div>
</div>
{/* Recent Activity */}
<div
className="rounded-2xl p-6"
style={{
backgroundColor: "var(--card-bg)",
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<div className="flex justify-between items-center mb-6">
<h3
className="text-xl font-bold"
style={{ color: "var(--text-primary)" }}
>
Последние события
</h3>
<Activity
className="w-5 h-5"
style={{ color: "var(--text-muted)" }}
/>
</div>
<div className="space-y-4">
{recentActivities.map((activity) => {
const severityStyles = getSeverityStyles(activity.severity);
const Icon = severityStyles.icon;
return (
<div
key={activity.id}
className="p-3 rounded-lg transition-all hover:scale-[1.01]"
style={{
backgroundColor: "var(--bg-secondary)",
}}
>
<div className="flex gap-3">
<div className="flex-shrink-0">
<Icon
className="w-4 h-4 mt-0.5"
style={{ color: severityStyles.text }}
/>
</div>
<div className="flex-1 min-w-0">
<p
className="text-sm mb-1"
style={{ color: "var(--text-primary)" }}
>
{activity.message}
</p>
<div className="flex items-center gap-2">
<Clock
className="w-3 h-3"
style={{ color: "var(--text-muted)" }}
/>
<p
className="text-xs"
style={{ color: "var(--text-muted)" }}
>
{activity.time}
</p>
</div>
</div>
</div>
</div>
);
})}
</div>
<button
className="w-full mt-4 py-2 rounded-lg text-sm font-medium transition-all hover:scale-[1.02]"
style={{
backgroundColor: "var(--bg-secondary)",
color: "var(--text-secondary)",
}}
>
Показать всю историю
</button>
</div>
</div>
{/* AI Insights */}
<div
className="rounded-2xl p-6 mt-8 transition-all hover:shadow-xl"
style={{
backgroundColor: "var(--card-bg)",
border: `1px solid var(--border)`,
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4 mb-6">
<div className="flex items-center gap-3">
<div
className="w-10 h-10 rounded-xl flex items-center justify-center"
style={{ backgroundColor: "#8b5cf620" }}
>
<Bot className="w-5 h-5" style={{ color: "#8b5cf6" }} />
</div>
<div>
<h3
className="text-xl font-bold"
style={{ color: "var(--text-primary)" }}
>
AI Аналитика
</h3>
<p
className="text-sm"
style={{ color: "var(--text-secondary)" }}
>
Новые предложения на основе анализа логов
</p>
</div>
</div>
<button
className="px-4 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2 hover:scale-[1.02] self-start"
style={{
backgroundColor: "#8b5cf6",
color: "white",
}}
>
Подробнее
<ChevronRight className="w-4 h-4" />
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
style={{ backgroundColor: "var(--bg-secondary)" }}
>
<p
className="text-sm font-medium mb-2"
style={{ color: "var(--text-primary)" }}
>
🔍 Обнаружена аномалия
</p>
<p
className="text-xs"
style={{ color: "var(--text-secondary)" }}
>
Повышенная активность с IP-адресов из диапазона
185.xxx.xx.xx
</p>
</div>
<div
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
style={{ backgroundColor: "var(--bg-secondary)" }}
>
<p
className="text-sm font-medium mb-2"
style={{ color: "var(--text-primary)" }}
>
💡 Предложено правил
</p>
<p
className="text-xs"
style={{ color: "var(--text-secondary)" }}
>
AI предлагает 3 новых правила для блокировки бот-сканеров
</p>
</div>
<div
className="p-4 rounded-xl transition-all hover:scale-[1.02]"
style={{ backgroundColor: "var(--bg-secondary)" }}
>
<p
className="text-sm font-medium mb-2"
style={{ color: "var(--text-primary)" }}
>
Оптимизация
</p>
<p
className="text-xs"
style={{ color: "var(--text-secondary)" }}
>
Рекомендуется обновить 5 существующих правил для повышения
эффективности
</p>
</div>
</div>
</div>
</>
) : (
/* CTA Section для неавторизованных */
<div
className="rounded-2xl p-8 text-center"
style={{
backgroundColor: "var(--card-bg)",
boxShadow: `0 4px 6px -1px var(--shadow-color)`,
}}
>
<h3
className="text-2xl font-bold mb-2"
style={{ color: "var(--text-primary)" }}
>
Готовы начать?
</h3>
<p
className="text-sm mb-6"
style={{ color: "var(--text-secondary)" }}
>
Присоединяйтесь к IPS Manager и получите полный контроль над
безопасностью
</p>
<button
onClick={() => navigate("/auth")}
className="px-6 py-2 rounded-lg font-medium transition-all hover:scale-105"
style={{
backgroundColor: "var(--accent)",
color: "white",
}}
>
Начать работу
</button>
</div>
)}
</main>
</div>
);
};