diff --git a/src/pages/AdminDashboard.tsx b/src/pages/AdminDashboard.tsx index cf6d8dc..4815ecc 100644 --- a/src/pages/AdminDashboard.tsx +++ b/src/pages/AdminDashboard.tsx @@ -4,7 +4,7 @@ import { Link } from 'react-router-dom' import { statsApi, type DashboardStats, type NodeStatus } from '../api/admin' import { useCurrency } from '../hooks/useCurrency' -// Icons +// Icons - styled like main navigation const BackIcon = () => ( @@ -12,26 +12,45 @@ const BackIcon = () => ( ) const ServerIcon = () => ( - - + + ) -const UsersIcon = () => ( - - +const UsersOnlineIcon = () => ( + + ) -const CurrencyIcon = () => ( - - +const WalletIcon = () => ( + + ) -const SubscriptionIcon = () => ( - - +const ChartBarIcon = () => ( + + + +) + +const SparklesIcon = () => ( + + + +) + +const CubeIcon = () => ( + + + +) + +const TagIcon = () => ( + + + ) @@ -319,26 +338,26 @@ export default function AdminDashboard() { } + icon={} color="success" /> } + icon={} color="accent" /> } + icon={} color="warning" /> } + icon={} color="info" /> @@ -347,7 +366,9 @@ export default function AdminDashboard() {
- +
+ +

{t('adminDashboard.nodes.title')}

@@ -395,7 +416,9 @@ export default function AdminDashboard() { {/* Revenue Chart */}

- +
+ +

{t('adminDashboard.revenue.title')}

{t('adminDashboard.revenue.last7Days')}

@@ -417,7 +440,9 @@ export default function AdminDashboard() { {/* Subscription Stats */}
- +
+ +

{t('adminDashboard.subscriptions.title')}

{t('adminDashboard.subscriptions.subtitle')}

@@ -478,7 +503,9 @@ export default function AdminDashboard() { {stats?.servers && (
- +
+ +

{t('adminDashboard.servers.title')}

@@ -506,7 +533,9 @@ export default function AdminDashboard() { {stats?.tariff_stats && stats.tariff_stats.tariffs.length > 0 && (
- +
+ +

{t('adminDashboard.tariffs.title')}

{t('adminDashboard.tariffs.subtitle')}

diff --git a/src/pages/AdminPanel.tsx b/src/pages/AdminPanel.tsx index e386d8a..2743827 100644 --- a/src/pages/AdminPanel.tsx +++ b/src/pages/AdminPanel.tsx @@ -1,393 +1,331 @@ import { Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' -// Icons - smaller versions for mobile -const TicketIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - +// Modern icons with consistent styling +const ChartBarIcon = () => ( + + + +) + +const BanknotesIcon = () => ( + + + +) + +const UsersIcon = () => ( + + + +) + +const ChatBubbleIcon = () => ( + + + +) + +const NoSymbolIcon = () => ( + + + +) + +const CreditCardIcon = () => ( + + + +) + +const TicketIcon = () => ( + ) -const CogIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - +const GiftIcon = () => ( + + + +) + +const MegaphoneIcon = () => ( + + + +) + +const PaperAirplaneIcon = () => ( + + + +) + +const SparklesIcon = () => ( + + + +) + +const CogIcon = () => ( + ) -const PhoneIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - +const DevicePhoneMobileIcon = () => ( + ) -const WheelIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const TariffIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const ServerIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - +const ServerStackIcon = () => ( + ) -const AdminIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const ChartIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const BanSystemIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const BroadcastIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const PromocodeIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const CampaignIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const UsersIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const PaymentsIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const PromoOffersIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - - -) - -const RemnawaveIcon = ({ className = "w-8 h-8" }: { className?: string }) => ( - - +const CubeTransparentIcon = () => ( + + ) const ChevronRightIcon = () => ( - + ) -interface AdminSection { +interface AdminItem { to: string icon: React.ReactNode - mobileIcon: React.ReactNode title: string description: string - color: string - bgColor: string - textColor: string } -// Mobile compact card -function MobileAdminCard({ to, mobileIcon, title, bgColor, textColor }: AdminSection) { +interface AdminGroup { + id: string + title: string + icon: string + gradient: string + borderColor: string + iconBg: string + iconColor: string + items: AdminItem[] +} + +function AdminCard({ to, icon, title, description, iconBg, iconColor }: AdminItem & { iconBg: string; iconColor: string }) { return ( -
-
- {mobileIcon} -
-
- {title} - - ) -} - -// Desktop card -function DesktopAdminCard({ to, icon, title, description, bgColor, textColor }: AdminSection) { - return ( - -
-
- {icon} -
+
+ {icon}
-

{title}

-

{description}

+

{title}

+

{description}

+
+
+
- ) } -// Section group definition -interface SectionGroup { - title: string - emoji: string - sections: AdminSection[] -} - -export default function AdminPanel() { - const { t } = useTranslation() - - // Grouped admin sections - const sectionGroups: SectionGroup[] = [ - { - title: 'Аналитика', - emoji: '📊', - sections: [ - { - to: '/admin/dashboard', - icon: , - mobileIcon: , - title: t('admin.nav.dashboard'), - description: t('admin.panel.dashboardDesc'), - color: 'success', - bgColor: 'bg-emerald-500/20', - textColor: 'text-emerald-400' - }, - { - to: '/admin/payments', - icon: , - mobileIcon: , - title: t('admin.nav.payments', 'Платежи'), - description: t('admin.panel.paymentsDesc', 'Проверка платежей'), - color: 'lime', - bgColor: 'bg-lime-500/20', - textColor: 'text-lime-400' - }, - ] - }, - { - title: 'Пользователи', - emoji: '👥', - sections: [ - { - to: '/admin/users', - icon: , - mobileIcon: , - title: t('admin.nav.users', 'Пользователи'), - description: t('admin.panel.usersDesc', 'Управление пользователями'), - color: 'indigo', - bgColor: 'bg-indigo-500/20', - textColor: 'text-indigo-400' - }, - { - to: '/admin/tickets', - icon: , - mobileIcon: , - title: t('admin.nav.tickets'), - description: t('admin.panel.ticketsDesc'), - color: 'warning', - bgColor: 'bg-amber-500/20', - textColor: 'text-amber-400' - }, - { - to: '/admin/ban-system', - icon: , - mobileIcon: , - title: t('admin.nav.banSystem'), - description: t('admin.panel.banSystemDesc'), - color: 'error', - bgColor: 'bg-red-500/20', - textColor: 'text-red-400' - }, - ] - }, - { - title: 'Тарифы и продажи', - emoji: '💰', - sections: [ - { - to: '/admin/tariffs', - icon: , - mobileIcon: , - title: t('admin.nav.tariffs'), - description: t('admin.panel.tariffsDesc'), - color: 'info', - bgColor: 'bg-cyan-500/20', - textColor: 'text-cyan-400' - }, - { - to: '/admin/promocodes', - icon: , - mobileIcon: , - title: t('admin.nav.promocodes', 'Промокоды'), - description: t('admin.panel.promocodesDesc', 'Управление промокодами'), - color: 'violet', - bgColor: 'bg-violet-500/20', - textColor: 'text-violet-400' - }, - { - to: '/admin/promo-offers', - icon: , - mobileIcon: , - title: t('admin.nav.promoOffers', 'Промопредложения'), - description: t('admin.panel.promoOffersDesc', 'Персональные скидки и предложения'), - color: 'orange', - bgColor: 'bg-orange-500/20', - textColor: 'text-orange-400' - }, - ] - }, - { - title: 'Маркетинг', - emoji: '📣', - sections: [ - { - to: '/admin/campaigns', - icon: , - mobileIcon: , - title: t('admin.nav.campaigns', 'Кампании'), - description: t('admin.panel.campaignsDesc', 'Рекламные кампании'), - color: 'orange', - bgColor: 'bg-orange-500/20', - textColor: 'text-orange-400' - }, - { - to: '/admin/broadcasts', - icon: , - mobileIcon: , - title: t('admin.nav.broadcasts'), - description: t('admin.panel.broadcastsDesc'), - color: 'orange', - bgColor: 'bg-orange-500/20', - textColor: 'text-orange-400' - }, - { - to: '/admin/wheel', - icon: , - mobileIcon: , - title: t('admin.nav.wheel'), - description: t('admin.panel.wheelDesc'), - color: 'error', - bgColor: 'bg-rose-500/20', - textColor: 'text-rose-400' - }, - ] - }, - { - title: 'Система', - emoji: '⚙️', - sections: [ - { - to: '/admin/settings', - icon: , - mobileIcon: , - title: t('admin.nav.settings'), - description: t('admin.panel.settingsDesc'), - color: 'accent', - bgColor: 'bg-blue-500/20', - textColor: 'text-blue-400' - }, - { - to: '/admin/apps', - icon: , - mobileIcon: , - title: t('admin.nav.apps'), - description: t('admin.panel.appsDesc'), - color: 'success', - bgColor: 'bg-teal-500/20', - textColor: 'text-teal-400' - }, - { - to: '/admin/servers', - icon: , - mobileIcon: , - title: t('admin.nav.servers'), - description: t('admin.panel.serversDesc'), - color: 'purple', - bgColor: 'bg-purple-500/20', - textColor: 'text-purple-400' - }, - { - to: '/admin/remnawave', - icon: , - mobileIcon: , - title: t('admin.nav.remnawave', 'RemnaWave'), - description: t('admin.panel.remnawaveDesc', 'Управление панелью и статистика'), - color: 'purple', - bgColor: 'bg-purple-500/20', - textColor: 'text-purple-400' - }, - ] - }, - ] - - // Flatten all sections for mobile view - const allSections = sectionGroups.flatMap(group => group.sections) - +function GroupSection({ group }: { group: AdminGroup }) { return ( -
- {/* Header - compact on mobile */} -
-
- -
-
-

{t('admin.panel.title')}

-

{t('admin.panel.subtitle')}

+
+ {/* Group Header */} +
+
+ {group.icon} +

{group.title}

- {/* Mobile: Compact grid (all sections) */} -
- {allSections.map((section) => ( - - ))} -
- - {/* Tablet/Desktop: Grouped sections */} -
- {sectionGroups.map((group) => ( -
- {/* Group header */} -
- {group.emoji} -

{group.title}

-
- - {/* Group cards */} -
- {group.sections.map((section) => ( - - ))} -
-
+ {/* Group Items */} +
+ {group.items.map((item) => ( + + ))} +
+
+ ) +} + +export default function AdminPanel() { + const { t } = useTranslation() + + const groups: AdminGroup[] = [ + { + id: 'analytics', + title: t('admin.groups.analytics', 'Аналитика'), + icon: '📊', + gradient: 'from-emerald-500/10 to-emerald-500/5', + borderColor: 'border-emerald-500/20', + iconBg: 'bg-emerald-500/20', + iconColor: 'text-emerald-400', + items: [ + { + to: '/admin/dashboard', + icon: , + title: t('admin.nav.dashboard'), + description: t('admin.panel.dashboardDesc'), + }, + { + to: '/admin/payments', + icon: , + title: t('admin.nav.payments', 'Платежи'), + description: t('admin.panel.paymentsDesc', 'История и проверка платежей'), + }, + ], + }, + { + id: 'users', + title: t('admin.groups.users', 'Пользователи'), + icon: '👥', + gradient: 'from-blue-500/10 to-blue-500/5', + borderColor: 'border-blue-500/20', + iconBg: 'bg-blue-500/20', + iconColor: 'text-blue-400', + items: [ + { + to: '/admin/users', + icon: , + title: t('admin.nav.users', 'Пользователи'), + description: t('admin.panel.usersDesc', 'Управление пользователями'), + }, + { + to: '/admin/tickets', + icon: , + title: t('admin.nav.tickets'), + description: t('admin.panel.ticketsDesc'), + }, + { + to: '/admin/ban-system', + icon: , + title: t('admin.nav.banSystem'), + description: t('admin.panel.banSystemDesc'), + }, + ], + }, + { + id: 'tariffs', + title: t('admin.groups.tariffs', 'Тарифы и продажи'), + icon: '💰', + gradient: 'from-amber-500/10 to-amber-500/5', + borderColor: 'border-amber-500/20', + iconBg: 'bg-amber-500/20', + iconColor: 'text-amber-400', + items: [ + { + to: '/admin/tariffs', + icon: , + title: t('admin.nav.tariffs'), + description: t('admin.panel.tariffsDesc'), + }, + { + to: '/admin/promocodes', + icon: , + title: t('admin.nav.promocodes', 'Промокоды'), + description: t('admin.panel.promocodesDesc', 'Управление промокодами'), + }, + { + to: '/admin/promo-offers', + icon: , + title: t('admin.nav.promoOffers', 'Промопредложения'), + description: t('admin.panel.promoOffersDesc', 'Персональные скидки'), + }, + ], + }, + { + id: 'marketing', + title: t('admin.groups.marketing', 'Маркетинг'), + icon: '📣', + gradient: 'from-rose-500/10 to-rose-500/5', + borderColor: 'border-rose-500/20', + iconBg: 'bg-rose-500/20', + iconColor: 'text-rose-400', + items: [ + { + to: '/admin/campaigns', + icon: , + title: t('admin.nav.campaigns', 'Кампании'), + description: t('admin.panel.campaignsDesc', 'Рекламные кампании'), + }, + { + to: '/admin/broadcasts', + icon: , + title: t('admin.nav.broadcasts'), + description: t('admin.panel.broadcastsDesc'), + }, + { + to: '/admin/wheel', + icon: , + title: t('admin.nav.wheel'), + description: t('admin.panel.wheelDesc'), + }, + ], + }, + { + id: 'system', + title: t('admin.groups.system', 'Система'), + icon: '⚙️', + gradient: 'from-violet-500/10 to-violet-500/5', + borderColor: 'border-violet-500/20', + iconBg: 'bg-violet-500/20', + iconColor: 'text-violet-400', + items: [ + { + to: '/admin/settings', + icon: , + title: t('admin.nav.settings'), + description: t('admin.panel.settingsDesc'), + }, + { + to: '/admin/apps', + icon: , + title: t('admin.nav.apps'), + description: t('admin.panel.appsDesc'), + }, + { + to: '/admin/servers', + icon: , + title: t('admin.nav.servers'), + description: t('admin.panel.serversDesc'), + }, + { + to: '/admin/remnawave', + icon: , + title: t('admin.nav.remnawave', 'RemnaWave'), + description: t('admin.panel.remnawaveDesc', 'Управление панелью'), + }, + ], + }, + ] + + return ( +
+ {/* Header */} +
+

{t('admin.panel.title')}

+

{t('admin.panel.subtitle')}

+
+ + {/* Groups Grid */} +
+ {groups.map((group) => ( + ))}