import { createEffect, createSignal, For, on, Show } from 'solid-js' import { Topic, useData } from '../context/data' import { useTableSort } from '../context/sort' import { TOPICS_SORT_CONFIG } from '../context/sortConfig' import TopicEditModal from '../modals/TopicEditModal' import adminStyles from '../styles/Admin.module.css' import styles from '../styles/Table.module.css' import SortableHeader from '../ui/SortableHeader' import TableControls from '../ui/TableControls' interface TopicsProps { onError?: (message: string) => void onSuccess?: (message: string) => void } export const Topics = (props: TopicsProps) => { const { selectedCommunity, loadTopicsByCommunity, topics: contextTopics, getTopicTitle } = useData() // Состояние поиска const [searchQuery, setSearchQuery] = createSignal('') // Состояние загрузки const [loading, setLoading] = createSignal(false) // Модальное окно для редактирования топика const [showEditModal, setShowEditModal] = createSignal(false) const [selectedTopic, setSelectedTopic] = createSignal(undefined) // Сортировка const { sortState } = useTableSort() /** * Загрузка топиков для сообщества */ async function loadTopicsForCommunity() { const community = selectedCommunity() // selectedCommunity теперь всегда число (по умолчанию 1) console.log('[TopicsRoute] Loading all topics for community...') try { setLoading(true) // Загружаем все топики сообщества await loadTopicsByCommunity(community!) console.log('[TopicsRoute] All topics loaded') } catch (error) { console.error('[TopicsRoute] Failed to load topics:', error) props.onError?.(error instanceof Error ? error.message : 'Не удалось загрузить список топиков') } finally { setLoading(false) } } /** * Обработчик поиска - применяет поисковый запрос */ const handleSearch = () => { // Поиск осуществляется через filteredTopics(), которая реагирует на searchQuery() // Дополнительная логика поиска здесь не нужна, но можно добавить аналитику console.log('[TopicsRoute] Search triggered with query:', searchQuery()) } /** * Фильтрация топиков по поисковому запросу */ const filteredTopics = () => { const topics = contextTopics() const query = searchQuery().toLowerCase() if (!query) return topics return topics.filter( (topic) => topic.title?.toLowerCase().includes(query) || topic.slug?.toLowerCase().includes(query) || topic.id.toString().includes(query) ) } /** * Сортировка топиков на клиенте */ const sortedTopics = () => { const topics = filteredTopics() const { field, direction } = sortState() return [...topics].sort((a, b) => { let comparison = 0 switch (field) { case 'id': comparison = a.id - b.id break case 'title': comparison = (a.title || '').localeCompare(b.title || '', 'ru') break case 'slug': comparison = (a.slug || '').localeCompare(b.slug || '', 'ru') break default: comparison = a.id - b.id } return direction === 'desc' ? -comparison : comparison }) } // Загрузка при смене сообщества createEffect( on(selectedCommunity, (updatedCommunity) => { if (updatedCommunity) { // selectedCommunity теперь всегда число, поэтому всегда загружаем void loadTopicsForCommunity() } }) ) const truncateText = (text: string, maxLength = 100): string => { if (!text || text.length <= maxLength) return text return `${text.substring(0, maxLength)}...` } /** * Открытие модального окна редактирования топика */ const handleTopicEdit = (topic: Topic) => { console.log('[TopicsRoute] Opening edit modal for topic:', topic) setSelectedTopic(topic) setShowEditModal(true) } /** * Сохранение изменений топика */ const handleTopicSave = async (updatedTopic: Topic) => { console.log('[TopicsRoute] Saving topic:', updatedTopic) console.log('[TopicsRoute] Topic parent_ids:', updatedTopic.parent_ids) // Сразу обновляем локальные данные для мгновенного отображения const currentTopics = contextTopics() console.log('[TopicsRoute] Current topics count:', currentTopics.length) const updatedTopics = currentTopics.map(topic => topic.id === updatedTopic.id ? updatedTopic : topic ) console.log('[TopicsRoute] Updated topics count:', updatedTopics.length) // Обновляем состояние контекста напрямую (это сработает мгновенно) const { setTopics } = useData() setTopics(updatedTopics) props.onSuccess?.('Топик успешно обновлён') // Ждем большее время чтобы сервер точно обработал изменения и инвалидировал кеш console.log('[TopicsRoute] Scheduling reload in 500ms...') setTimeout(() => { console.log('[TopicsRoute] Reloading topics from server...') void loadTopicsForCommunity() }, 500) } /** * Обработка ошибок из модального окна */ const handleTopicError = (message: string) => { props.onError?.(message) } /** * Рендер родительских тем для топика */ const renderParentTopics = (parentIds?: number[]) => { if (!parentIds || parentIds.length === 0) { return Нет родителей } return (
{(parentId) => { const parentTitle = getTopicTitle(parentId) return ( #{parentTitle || `ID:${parentId}`} ) }}
) } /** * Рендер строки топика */ const renderTopicRow = (topic: Topic) => ( handleTopicEdit(topic)} style="cursor: pointer;" title="Нажмите для редактирования топика" > {topic.id} {truncateText(topic.title, 50)} {truncateText(topic.slug, 30)} {renderParentTopics(topic.parent_ids)} {topic.body ? ( {truncateText(topic.body.replace(/<[^>]*>/g, ''), 60)} ) : ( Нет содержимого )} ) return (
ID Название Slug {renderTopicRow}
Родительские темы Body
Загрузка...
Нет топиков
{/* Модальное окно для редактирования топика */} { setShowEditModal(false) setSelectedTopic(undefined) }} onSave={handleTopicSave} onError={handleTopicError} />
) }