2025-05-16 06:23:48 +00:00
|
|
|
|
/**
|
|
|
|
|
* Компонент страницы администратора
|
|
|
|
|
* @module AdminPage
|
|
|
|
|
*/
|
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
import { useNavigate, useParams } from '@solidjs/router'
|
|
|
|
|
import { Component, createEffect, createSignal, onMount, Show } from 'solid-js'
|
|
|
|
|
import publyLogo from './assets/publy.svg?url'
|
|
|
|
|
import { logout } from './context/auth'
|
|
|
|
|
// Прямой импорт компонентов вместо ленивой загрузки
|
|
|
|
|
import AuthorsRoute from './routes/authors'
|
|
|
|
|
import CommunitiesRoute from './routes/communities'
|
|
|
|
|
import EnvRoute from './routes/env'
|
|
|
|
|
import ShoutsRoute from './routes/shouts'
|
|
|
|
|
import TopicsRoute from './routes/topics'
|
|
|
|
|
import styles from './styles/Admin.module.css'
|
|
|
|
|
import Button from './ui/Button'
|
2025-06-28 10:47:08 +00:00
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
/**
|
|
|
|
|
* Интерфейс свойств компонента AdminPage
|
|
|
|
|
*/
|
2025-06-30 18:25:26 +00:00
|
|
|
|
export interface AdminPageProps {
|
2025-05-20 22:34:02 +00:00
|
|
|
|
apiUrl: string
|
2025-05-16 07:30:02 +00:00
|
|
|
|
onLogout?: () => void
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
/**
|
|
|
|
|
* Компонент страницы администратора
|
|
|
|
|
*/
|
2025-05-16 07:30:02 +00:00
|
|
|
|
const AdminPage: Component<AdminPageProps> = (props) => {
|
2025-06-30 18:25:26 +00:00
|
|
|
|
console.log('[AdminPage] Initializing...')
|
|
|
|
|
const navigate = useNavigate()
|
|
|
|
|
const params = useParams()
|
2025-05-16 06:23:48 +00:00
|
|
|
|
const [error, setError] = createSignal<string | null>(null)
|
|
|
|
|
const [successMessage, setSuccessMessage] = createSignal<string | null>(null)
|
2025-06-30 18:25:26 +00:00
|
|
|
|
const [currentTab, setCurrentTab] = createSignal<string>('authors')
|
2025-05-20 22:34:02 +00:00
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
onMount(() => {
|
|
|
|
|
console.log('[AdminPage] Component mounted')
|
|
|
|
|
console.log('[AdminPage] Initial params:', params)
|
|
|
|
|
// Если мы на корневом пути /admin, редиректим на /admin/authors
|
|
|
|
|
if (!params.tab) {
|
|
|
|
|
navigate('/admin/authors', { replace: true })
|
|
|
|
|
} else {
|
|
|
|
|
setCurrentTab(params.tab)
|
|
|
|
|
}
|
2025-05-16 06:23:48 +00:00
|
|
|
|
})
|
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
// Отслеживаем изменения параметров роута
|
|
|
|
|
createEffect(() => {
|
|
|
|
|
console.log('[AdminPage] Params changed:', params)
|
|
|
|
|
console.log('[AdminPage] Current tab param:', params.tab)
|
|
|
|
|
const newTab = params.tab || 'authors'
|
|
|
|
|
setCurrentTab(newTab)
|
|
|
|
|
console.log('[AdminPage] Updated currentTab to:', newTab)
|
2025-06-28 10:47:08 +00:00
|
|
|
|
})
|
2025-05-16 06:23:48 +00:00
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
// Определяем активную вкладку
|
|
|
|
|
const activeTab = () => {
|
|
|
|
|
const tab = currentTab()
|
|
|
|
|
console.log('[AdminPage] activeTab() returning:', tab)
|
|
|
|
|
return tab
|
2025-05-16 06:23:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-05-20 22:34:02 +00:00
|
|
|
|
* Обрабатывает выход из системы
|
2025-05-16 06:23:48 +00:00
|
|
|
|
*/
|
2025-05-20 22:34:02 +00:00
|
|
|
|
const handleLogout = async () => {
|
|
|
|
|
try {
|
|
|
|
|
await logout()
|
2025-05-16 07:30:02 +00:00
|
|
|
|
if (props.onLogout) {
|
|
|
|
|
props.onLogout()
|
|
|
|
|
}
|
2025-06-30 18:25:26 +00:00
|
|
|
|
navigate('/login')
|
2025-05-20 22:34:02 +00:00
|
|
|
|
} catch (error) {
|
2025-06-30 18:25:26 +00:00
|
|
|
|
setError(`Ошибка при выходе: ${(error as Error).message}`)
|
2025-05-20 22:34:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-30 18:25:26 +00:00
|
|
|
|
* Обработчик ошибок
|
2025-05-20 22:34:02 +00:00
|
|
|
|
*/
|
2025-06-30 18:25:26 +00:00
|
|
|
|
const handleError = (error: string) => {
|
|
|
|
|
setError(error)
|
|
|
|
|
// Скрываем ошибку через 5 секунд
|
|
|
|
|
setTimeout(() => setError(null), 5000)
|
2025-05-20 22:34:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-30 18:25:26 +00:00
|
|
|
|
* Обработчик успешных операций
|
2025-05-20 22:34:02 +00:00
|
|
|
|
*/
|
2025-06-30 18:25:26 +00:00
|
|
|
|
const handleSuccess = (message: string) => {
|
|
|
|
|
setSuccessMessage(message)
|
|
|
|
|
// Скрываем сообщение через 3 секунды
|
|
|
|
|
setTimeout(() => setSuccessMessage(null), 3000)
|
2025-06-28 11:52:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-16 06:23:48 +00:00
|
|
|
|
return (
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<div class={styles['admin-panel']}>
|
2025-05-16 06:23:48 +00:00
|
|
|
|
<header>
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<div class={styles['header-container']}>
|
|
|
|
|
<div class={styles['header-left']}>
|
|
|
|
|
<img src={publyLogo} alt="Logo" class={styles.logo} />
|
|
|
|
|
<h1>Панель администратора</h1>
|
|
|
|
|
</div>
|
|
|
|
|
<button class={styles['logout-button']} onClick={handleLogout}>
|
2025-05-16 06:23:48 +00:00
|
|
|
|
Выйти
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<nav class={styles['admin-tabs']}>
|
|
|
|
|
<Button
|
|
|
|
|
variant={activeTab() === 'authors' ? 'primary' : 'secondary'}
|
|
|
|
|
onClick={() => navigate('/admin/authors')}
|
|
|
|
|
>
|
|
|
|
|
Авторы
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant={activeTab() === 'shouts' ? 'primary' : 'secondary'}
|
|
|
|
|
onClick={() => navigate('/admin/shouts')}
|
|
|
|
|
>
|
2025-06-28 10:47:08 +00:00
|
|
|
|
Публикации
|
2025-06-30 18:25:26 +00:00
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant={activeTab() === 'topics' ? 'primary' : 'secondary'}
|
|
|
|
|
onClick={() => navigate('/admin/topics')}
|
|
|
|
|
>
|
|
|
|
|
Темы
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant={activeTab() === 'communities' ? 'primary' : 'secondary'}
|
|
|
|
|
onClick={() => navigate('/admin/communities')}
|
|
|
|
|
>
|
|
|
|
|
Сообщества
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant={activeTab() === 'env' ? 'primary' : 'secondary'}
|
|
|
|
|
onClick={() => navigate('/admin/env')}
|
|
|
|
|
>
|
2025-05-20 22:34:02 +00:00
|
|
|
|
Переменные среды
|
2025-06-30 18:25:26 +00:00
|
|
|
|
</Button>
|
2025-05-16 06:23:48 +00:00
|
|
|
|
</nav>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<main>
|
|
|
|
|
<Show when={error()}>
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<div class={styles['error-message']}>{error()}</div>
|
2025-05-16 06:23:48 +00:00
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={successMessage()}>
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<div class={styles['success-message']}>{successMessage()}</div>
|
2025-05-16 06:23:48 +00:00
|
|
|
|
</Show>
|
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
{/* Используем Show компоненты для каждой вкладки */}
|
|
|
|
|
<Show when={activeTab() === 'authors'}>
|
|
|
|
|
<AuthorsRoute onError={handleError} onSuccess={handleSuccess} />
|
2025-05-20 22:34:02 +00:00
|
|
|
|
</Show>
|
|
|
|
|
|
2025-06-28 10:47:08 +00:00
|
|
|
|
<Show when={activeTab() === 'shouts'}>
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<ShoutsRoute onError={handleError} onSuccess={handleSuccess} />
|
|
|
|
|
</Show>
|
2025-06-28 10:47:08 +00:00
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<Show when={activeTab() === 'topics'}>
|
|
|
|
|
<TopicsRoute onError={handleError} onSuccess={handleSuccess} />
|
|
|
|
|
</Show>
|
2025-06-28 10:47:08 +00:00
|
|
|
|
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<Show when={activeTab() === 'communities'}>
|
|
|
|
|
<CommunitiesRoute onError={handleError} onSuccess={handleSuccess} />
|
2025-06-28 10:47:08 +00:00
|
|
|
|
</Show>
|
|
|
|
|
|
2025-05-20 22:34:02 +00:00
|
|
|
|
<Show when={activeTab() === 'env'}>
|
2025-06-30 18:25:26 +00:00
|
|
|
|
<EnvRoute onError={handleError} onSuccess={handleSuccess} />
|
2025-05-16 06:23:48 +00:00
|
|
|
|
</Show>
|
|
|
|
|
</main>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default AdminPage
|