import { Component, createSignal, For, Show } from 'solid-js' import styles from '../styles/Form.module.css' import Button from '../ui/Button' import Modal from '../ui/Modal' interface Topic { id: number title: string slug: string parent_ids?: number[] community: number } interface TopicBulkParentModalProps { isOpen: boolean onClose: () => void selectedTopicIds: number[] allTopics: Topic[] onSave: (changes: BulkParentChange[]) => void onError: (error: string) => void } interface BulkParentChange { topicId: number newParentIds: number[] oldParentIds: number[] } const TopicBulkParentModal: Component = (props) => { const [newParentId, setNewParentId] = createSignal(null) const [searchQuery, setSearchQuery] = createSignal('') const [actionType, setActionType] = createSignal<'set' | 'makeRoot'>('set') // Получаем выбранные топики const getSelectedTopics = () => { return props.allTopics.filter((topic) => props.selectedTopicIds.includes(topic.id)) } // Фильтрация доступных родителей const getAvailableParents = () => { const selectedIds = new Set(props.selectedTopicIds) return props.allTopics.filter((topic) => { // Исключаем выбранные топики if (selectedIds.has(topic.id)) return false // Исключаем топики, которые являются детьми выбранных const isChildOfSelected = props.selectedTopicIds.some((selectedId) => isDescendant(selectedId, topic.id) ) if (isChildOfSelected) return false // Фильтр по поисковому запросу const query = searchQuery().toLowerCase() if (query && !topic.title.toLowerCase().includes(query)) return false return true }) } // Проверка, является ли топик потомком другого const isDescendant = (ancestorId: number, descendantId: number): boolean => { const descendant = props.allTopics.find((t) => t.id === descendantId) if (!descendant || !descendant.parent_ids) return false return descendant.parent_ids.includes(ancestorId) } // Получение пути к корню const getTopicPath = (topicId: number): string => { const topic = props.allTopics.find((t) => t.id === topicId) if (!topic) return '' if (!topic.parent_ids || topic.parent_ids.length === 0) { return topic.title } const parentPath = getTopicPath(topic.parent_ids[topic.parent_ids.length - 1]) return `${parentPath} → ${topic.title}` } // Группировка топиков по сообществам const getTopicsByCommunity = () => { const selectedTopics = getSelectedTopics() const communities = new Map() selectedTopics.forEach((topic) => { if (!communities.has(topic.community)) { communities.set(topic.community, []) } communities.get(topic.community)!.push(topic) }) return communities } // Проверка совместимости действия const validateAction = (): string | null => { const communities = getTopicsByCommunity() if (communities.size > 1) { return 'Нельзя изменять иерархию тем из разных сообществ одновременно' } if (actionType() === 'set' && !newParentId()) { return 'Выберите родительскую тему' } const selectedParent = props.allTopics.find((t) => t.id === newParentId()) if (selectedParent) { const selectedCommunity = Array.from(communities.keys())[0] if (selectedParent.community !== selectedCommunity) { return 'Родительская тема должна быть из того же сообщества' } } return null } // Сохранение изменений const handleSave = () => { const validationError = validateAction() if (validationError) { props.onError(validationError) return } const changes: BulkParentChange[] = [] const selectedTopics = getSelectedTopics() selectedTopics.forEach((topic) => { let newParentIds: number[] = [] if (actionType() === 'set' && newParentId()) { const parentTopic = props.allTopics.find((t) => t.id === newParentId()) if (parentTopic) { newParentIds = [...(parentTopic.parent_ids || []), newParentId()!] } } changes.push({ topicId: topic.id, newParentIds, oldParentIds: topic.parent_ids || [] }) }) props.onSave(changes) } return (
{/* Проверка совместимости */} 1}>
⚠️ Выбраны темы из разных сообществ. Массовое изменение иерархии возможно только для тем одного сообщества.
{/* Список выбранных тем */}

Выбранные темы ({props.selectedTopicIds.length}):

{(topic) => (
{topic.title} #{topic.id} 0}>
Текущий путь: {getTopicPath(topic.id)}
)}
{/* Выбор действия */}

Выберите действие:

setActionType('set')} />
setActionType('makeRoot')} />
{/* Выбор родителя */}

Выбор родительской темы:

setSearchQuery(e.target.value)} placeholder="Поиск родительской темы..." class={styles.searchInput} />
{(topic) => (
setNewParentId(topic.id)} />
)}
{searchQuery() ? `Нет доступных тем для поиска "${searchQuery()}"` : 'Нет доступных родительских тем'}
{/* Предварительный просмотр изменений */}

Предварительный просмотр:

{(topic) => (
{topic.title}
Было: {topic.parent_ids?.length ? getTopicPath(topic.id) : 'Корневая тема'} Станет:{' '} {actionType() === 'makeRoot' ? 'Корневая тема' : newParentId() ? `${getTopicPath(newParentId()!)} → ${topic.title}` : ''}
)}
) } export default TopicBulkParentModal