import { useState, useEffect } from 'react' import { adminApi } from '@/api' import type { StaticContent } from '@/types' import { useToast } from '@/store/toast' import { NeonButton } from '@/components/ui' import { FileText, Plus, Pencil, X, Save, Code, Trash2 } from 'lucide-react' import { useConfirm } from '@/store/confirm' function formatDate(dateStr: string) { return new Date(dateStr).toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } export function AdminContentPage() { const [contents, setContents] = useState([]) const [loading, setLoading] = useState(true) const [editing, setEditing] = useState(null) const [creating, setCreating] = useState(false) const [saving, setSaving] = useState(false) // Form state const [formKey, setFormKey] = useState('') const [formTitle, setFormTitle] = useState('') const [formContent, setFormContent] = useState('') const toast = useToast() const confirm = useConfirm() useEffect(() => { loadContents() // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const loadContents = async () => { try { const data = await adminApi.listContent() setContents(data) } catch (err) { console.error('Failed to load contents:', err) toast.error('Ошибка загрузки контента') } finally { setLoading(false) } } const handleEdit = (content: StaticContent) => { setEditing(content) setFormKey(content.key) setFormTitle(content.title) setFormContent(content.content) setCreating(false) } const handleCreate = () => { setCreating(true) setEditing(null) setFormKey('') setFormTitle('') setFormContent('') } const handleCancel = () => { setEditing(null) setCreating(false) setFormKey('') setFormTitle('') setFormContent('') } const handleSave = async () => { if (!formTitle.trim() || !formContent.trim()) { toast.error('Заполните все поля') return } if (creating && !formKey.trim()) { toast.error('Введите ключ') return } setSaving(true) try { if (creating) { const newContent = await adminApi.createContent(formKey, formTitle, formContent) setContents([...contents, newContent]) toast.success('Контент создан') } else if (editing) { const updated = await adminApi.updateContent(editing.key, formTitle, formContent) setContents(contents.map(c => c.id === updated.id ? updated : c)) toast.success('Контент обновлён') } handleCancel() } catch (err) { console.error('Failed to save content:', err) toast.error('Ошибка сохранения') } finally { setSaving(false) } } const handleDelete = async (content: StaticContent) => { const confirmed = await confirm({ title: 'Удалить контент?', message: `Вы уверены, что хотите удалить "${content.title}"? Это действие нельзя отменить.`, confirmText: 'Удалить', cancelText: 'Отмена', variant: 'danger', }) if (!confirmed) return try { await adminApi.deleteContent(content.key) setContents(contents.filter(c => c.id !== content.id)) if (editing?.id === content.id) { handleCancel() } toast.success('Контент удалён') } catch (err) { console.error('Failed to delete content:', err) toast.error('Ошибка удаления') } } if (loading) { return (
) } return (
{/* Header */}

Статический контент

}> Добавить
{/* Content List */}
{contents.length === 0 ? (

Нет статического контента

Создайте первую страницу

) : ( contents.map((content) => (
handleEdit(content)} >

{content.key}

{content.title}

{content.content.replace(/<[^>]*>/g, '').slice(0, 100)}...

Обновлено: {formatDate(content.updated_at)}

)) )}
{/* Editor */} {(editing || creating) && (

{creating ? ( <> Новый контент ) : ( <> Редактирование )}

{creating && (
setFormKey(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, ''))} placeholder="about-page" className="w-full bg-dark-700/50 border border-dark-600 rounded-xl px-4 py-2.5 text-white font-mono placeholder:text-gray-500 focus:outline-none focus:border-accent-500/50 transition-colors" />

Только буквы, цифры, дефисы и подчеркивания

)}
setFormTitle(e.target.value)} placeholder="Заголовок страницы" className="w-full bg-dark-700/50 border border-dark-600 rounded-xl px-4 py-2.5 text-white placeholder:text-gray-500 focus:outline-none focus:border-accent-500/50 transition-colors" />