import { Component, createEffect, createSignal, For, on, onMount, Show, untrack } from 'solid-js' import { useTableSort } from '../context/sort' import { COMMUNITIES_SORT_CONFIG } from '../context/sortConfig' import { CREATE_COMMUNITY_MUTATION, DELETE_COMMUNITY_MUTATION, UPDATE_COMMUNITY_MUTATION } from '../graphql/mutations' import { GET_COMMUNITIES_QUERY } from '../graphql/queries' import CommunityEditModal from '../modals/CommunityEditModal' import styles from '../styles/Table.module.css' import Button from '../ui/Button' import Modal from '../ui/Modal' import SortableHeader from '../ui/SortableHeader' import TableControls from '../ui/TableControls' /** * Интерфейс для сообщества (используем локальный интерфейс для совместимости) */ interface Community { id: number slug: string name: string desc?: string pic: string created_at: number created_by: { id: number name: string email: string } stat: { shouts: number followers: number authors: number } } interface CommunitiesRouteProps { onError: (error: string) => void onSuccess: (message: string) => void } /** * Компонент для управления сообществами */ const CommunitiesRoute: Component = (props) => { const [communities, setCommunities] = createSignal([]) const [loading, setLoading] = createSignal(false) const { sortState } = useTableSort() const [editModal, setEditModal] = createSignal<{ show: boolean community: Community | null }>({ show: false, community: null }) const [deleteModal, setDeleteModal] = createSignal<{ show: boolean community: Community | null }>({ show: false, community: null }) const [createModal, setCreateModal] = createSignal<{ show: boolean }>({ show: false }) /** * Загружает список всех сообществ */ const loadCommunities = async () => { setLoading(true) try { // Загружаем все сообщества без параметров сортировки // Сортировка будет выполнена на клиенте const response = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: GET_COMMUNITIES_QUERY }) }) const result = await response.json() if (result.errors) { throw new Error(result.errors[0].message) } // Получаем данные и сортируем их на клиенте const communitiesData = result.data.get_communities_all || [] const sortedCommunities = sortCommunities(communitiesData) setCommunities(sortedCommunities) } catch (error) { props.onError(`Ошибка загрузки сообществ: ${(error as Error).message}`) } finally { setLoading(false) } } /** * Форматирует дату */ const formatDate = (timestamp: number): string => { return new Date(timestamp * 1000).toLocaleDateString('ru-RU') } /** * Сортирует сообщества на клиенте в соответствии с текущим состоянием сортировки */ const sortCommunities = (communities: Community[]): Community[] => { const { field, direction } = sortState() return [...communities].sort((a, b) => { let comparison = 0 switch (field) { case 'id': comparison = a.id - b.id break case 'name': comparison = (a.name || '').localeCompare(b.name || '', 'ru') break case 'slug': comparison = (a.slug || '').localeCompare(b.slug || '', 'ru') break case 'created_at': comparison = a.created_at - b.created_at break case 'created_by': { const aName = a.created_by?.name || a.created_by?.email || '' const bName = b.created_by?.name || b.created_by?.email || '' comparison = aName.localeCompare(bName, 'ru') break } case 'shouts': comparison = (a.stat?.shouts || 0) - (b.stat?.shouts || 0) break case 'followers': comparison = (a.stat?.followers || 0) - (b.stat?.followers || 0) break case 'authors': comparison = (a.stat?.authors || 0) - (b.stat?.authors || 0) break default: comparison = a.id - b.id } return direction === 'desc' ? -comparison : comparison }) } /** * Открывает модалку создания */ const openCreateModal = () => { setCreateModal({ show: true }) } /** * Открывает модалку редактирования */ const openEditModal = (community: Community) => { setEditModal({ show: true, community }) } /** * Обрабатывает сохранение сообщества (создание или обновление) */ const handleSaveCommunity = async (communityData: Partial) => { try { const isCreating = !editModal().community && createModal().show const mutation = isCreating ? CREATE_COMMUNITY_MUTATION : UPDATE_COMMUNITY_MUTATION const response = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: mutation, variables: { community_input: communityData } }) }) const result = await response.json() if (result.errors) { throw new Error(result.errors[0].message) } const resultData = isCreating ? result.data.create_community : result.data.update_community if (resultData.error) { throw new Error(resultData.error) } props.onSuccess(isCreating ? 'Сообщество успешно создано' : 'Сообщество успешно обновлено') setCreateModal({ show: false }) setEditModal({ show: false, community: null }) await loadCommunities() } catch (error) { props.onError( `Ошибка ${createModal().show ? 'создания' : 'обновления'} сообщества: ${(error as Error).message}` ) } } /** * Удаляет сообщество */ const deleteCommunity = async (slug: string) => { try { const response = await fetch('/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: DELETE_COMMUNITY_MUTATION, variables: { slug } }) }) const result = await response.json() if (result.errors) { throw new Error(result.errors[0].message) } if (result.data.delete_community.error) { throw new Error(result.data.delete_community.error) } props.onSuccess('Сообщество успешно удалено') setDeleteModal({ show: false, community: null }) await loadCommunities() } catch (error) { props.onError(`Ошибка удаления сообщества: ${(error as Error).message}`) } } // Пересортировка при изменении состояния сортировки createEffect( on([sortState], () => { if (communities().length > 0) { // Используем untrack для предотвращения бесконечной рекурсии const currentCommunities = untrack(() => communities()) const sortedCommunities = sortCommunities(currentCommunities) // Сравниваем текущий порядок с отсортированным, чтобы избежать лишних обновлений const needsUpdate = JSON.stringify(currentCommunities.map((c: Community) => c.id)) !== JSON.stringify(sortedCommunities.map((c: Community) => c.id)) if (needsUpdate) { setCommunities(sortedCommunities) } } }) ) // Загружаем сообщества при монтировании компонента onMount(() => { void loadCommunities() }) return (
Создать сообщество } />
Загрузка сообществ...
} > ID Название Slug Создатель Публикации Подписчики Создано {(community) => ( openEditModal(community)} style={{ cursor: 'pointer' }} class={styles['clickable-row']} > )}
Описание Авторы Действия
{community.id} {community.name} {community.slug}
{community.desc || '—'}
{community.created_by.name || community.created_by.email} {community.stat.shouts} {community.stat.followers} {community.stat.authors} {formatDate(community.created_at)} e.stopPropagation()}>
{/* Модальное окно создания */} setCreateModal({ show: false })} onSave={handleSaveCommunity} /> {/* Модальное окно редактирования */} setEditModal({ show: false, community: null })} onSave={handleSaveCommunity} /> {/* Модальное окно подтверждения удаления */} setDeleteModal({ show: false, community: null })} title="Подтверждение удаления" >

Вы уверены, что хотите удалить сообщество "{deleteModal().community?.name}"?

Это действие нельзя отменить. Все публикации и темы сообщества могут быть затронуты.

) } export default CommunitiesRoute