panel-improves

This commit is contained in:
2025-07-01 09:32:22 +03:00
parent 547c934302
commit 27a358a41f
10 changed files with 284 additions and 310 deletions

View File

@@ -1,7 +1,7 @@
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'
import styles from '../styles/Form.module.css'
interface Topic {
id: number
@@ -33,21 +33,19 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
// Получаем выбранные топики
const getSelectedTopics = () => {
return props.allTopics.filter(topic =>
props.selectedTopicIds.includes(topic.id)
)
return props.allTopics.filter((topic) => props.selectedTopicIds.includes(topic.id))
}
// Фильтрация доступных родителей
const getAvailableParents = () => {
const selectedIds = new Set(props.selectedTopicIds)
return props.allTopics.filter(topic => {
return props.allTopics.filter((topic) => {
// Исключаем выбранные топики
if (selectedIds.has(topic.id)) return false
// Исключаем топики, которые являются детьми выбранных
const isChildOfSelected = props.selectedTopicIds.some(selectedId =>
const isChildOfSelected = props.selectedTopicIds.some((selectedId) =>
isDescendant(selectedId, topic.id)
)
if (isChildOfSelected) return false
@@ -62,7 +60,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
// Проверка, является ли топик потомком другого
const isDescendant = (ancestorId: number, descendantId: number): boolean => {
const descendant = props.allTopics.find(t => t.id === descendantId)
const descendant = props.allTopics.find((t) => t.id === descendantId)
if (!descendant || !descendant.parent_ids) return false
return descendant.parent_ids.includes(ancestorId)
@@ -70,7 +68,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
// Получение пути к корню
const getTopicPath = (topicId: number): string => {
const topic = props.allTopics.find(t => t.id === topicId)
const topic = props.allTopics.find((t) => t.id === topicId)
if (!topic) return ''
if (!topic.parent_ids || topic.parent_ids.length === 0) {
@@ -86,7 +84,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
const selectedTopics = getSelectedTopics()
const communities = new Map<number, Topic[]>()
selectedTopics.forEach(topic => {
selectedTopics.forEach((topic) => {
if (!communities.has(topic.community)) {
communities.set(topic.community, [])
}
@@ -108,7 +106,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
return 'Выберите родительскую тему'
}
const selectedParent = props.allTopics.find(t => t.id === newParentId())
const selectedParent = props.allTopics.find((t) => t.id === newParentId())
if (selectedParent) {
const selectedCommunity = Array.from(communities.keys())[0]
if (selectedParent.community !== selectedCommunity) {
@@ -130,11 +128,11 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
const changes: BulkParentChange[] = []
const selectedTopics = getSelectedTopics()
selectedTopics.forEach(topic => {
selectedTopics.forEach((topic) => {
let newParentIds: number[] = []
if (actionType() === 'set' && newParentId()) {
const parentTopic = props.allTopics.find(t => t.id === newParentId())
const parentTopic = props.allTopics.find((t) => t.id === newParentId())
if (parentTopic) {
newParentIds = [...(parentTopic.parent_ids || []), newParentId()!]
}
@@ -161,7 +159,8 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
{/* Проверка совместимости */}
<Show when={getTopicsByCommunity().size > 1}>
<div class={styles.errorMessage}>
Выбраны темы из разных сообществ. Массовое изменение иерархии возможно только для тем одного сообщества.
Выбраны темы из разных сообществ. Массовое изменение иерархии возможно только для тем одного
сообщества.
</div>
</Show>
@@ -175,9 +174,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
<span class={styles.topicTitle}>{topic.title}</span>
<span class={styles.topicId}>#{topic.id}</span>
<Show when={topic.parent_ids && topic.parent_ids.length > 0}>
<div class={styles.currentPath}>
Текущий путь: {getTopicPath(topic.id)}
</div>
<div class={styles.currentPath}>Текущий путь: {getTopicPath(topic.id)}</div>
</Show>
</div>
)}
@@ -256,9 +253,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
<span class={styles.topicSlug}>{topic.slug}</span>
</div>
<Show when={topic.parent_ids && topic.parent_ids.length > 0}>
<div class={styles.parentPath}>
Текущий путь: {getTopicPath(topic.id)}
</div>
<div class={styles.parentPath}>Текущий путь: {getTopicPath(topic.id)}</div>
</Show>
</label>
</div>
@@ -270,8 +265,7 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
<div class={styles.noResults}>
{searchQuery()
? `Нет доступных тем для поиска "${searchQuery()}"`
: 'Нет доступных родительских тем'
}
: 'Нет доступных родительских тем'}
</div>
</Show>
</div>
@@ -292,11 +286,12 @@ const TopicBulkParentModal: Component<TopicBulkParentModalProps> = (props) => {
</span>
<span class={styles.arrow}></span>
<span class={styles.afterState}>
Станет: {
actionType() === 'makeRoot'
? 'Корневая тема'
: newParentId() ? `${getTopicPath(newParentId()!)}${topic.title}` : ''
}
Станет:{' '}
{actionType() === 'makeRoot'
? 'Корневая тема'
: newParentId()
? `${getTopicPath(newParentId()!)}${topic.title}`
: ''}
</span>
</div>
</div>

View File

@@ -1,7 +1,7 @@
import { Component, createSignal, For, Show } from 'solid-js'
import { Component, createSignal, For, JSX, Show } from 'solid-js'
import styles from '../styles/Form.module.css'
import Button from '../ui/Button'
import Modal from '../ui/Modal'
import styles from '../styles/Form.module.css'
// Типы для топиков
interface Topic {
@@ -28,7 +28,7 @@ interface HierarchyChange {
oldParentIds: number[]
}
const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
const TopicHierarchyModal = (props: TopicHierarchyModalProps) => {
const [localTopics, setLocalTopics] = createSignal<Topic[]>([])
const [changes, setChanges] = createSignal<HierarchyChange[]>([])
const [expandedNodes, setExpandedNodes] = createSignal<Set<number>>(new Set())
@@ -43,7 +43,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
setSearchQuery('')
setSelectedForMove(null)
// Раскрываем все узлы по умолчанию
const allIds = new Set(props.topics.map(t => t.id))
const allIds = new Set(props.topics.map((t) => t.id))
setExpandedNodes(allIds)
}
@@ -112,10 +112,8 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
// Обновление родителя топика
const updateTopicParent = (topicId: number, newParentIds: number[]) => {
const flatTopics = flattenTopics(localTopics())
const updatedTopics = flatTopics.map(topic =>
topic.id === topicId
? { ...topic, parent_ids: newParentIds }
: topic
const updatedTopics = flatTopics.map((topic) =>
topic.id === topicId ? { ...topic, parent_ids: newParentIds } : topic
)
const newHierarchy = buildHierarchy(updatedTopics)
setLocalTopics(newHierarchy)
@@ -125,7 +123,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
const flattenTopics = (topics: Topic[]): Topic[] => {
const result: Topic[] = []
const flatten = (topicList: Topic[]) => {
topicList.forEach(topic => {
topicList.forEach((topic) => {
result.push(topic)
if (topic.children) {
flatten(topic.children)
@@ -173,7 +171,9 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
setSelectedForMove(topicId)
const topic = findTopicById(topicId)
if (topic) {
props.onError(`Выбрана тема "${topic.title}" для перемещения. Теперь нажмите на новую родительскую тему или используйте "Сделать корневой".`)
props.onError(
`Выбрана тема "${topic.title}" для перемещения. Теперь нажмите на новую родительскую тему или используйте "Сделать корневой".`
)
}
}
@@ -203,8 +203,8 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
updateTopicParent(selectedId, newParentIds)
// Добавляем в список изменений
setChanges(prev => [
...prev.filter(c => c.topicId !== selectedId),
setChanges((prev) => [
...prev.filter((c) => c.topicId !== selectedId),
{
topicId: selectedId,
newParentIds,
@@ -222,14 +222,14 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
const expanded = expandedNodes()
// Раскрываем всех родителей
topic.parent_ids.forEach(parentId => {
topic.parent_ids.forEach((parentId) => {
expanded.add(parentId)
})
setExpandedNodes(new Set(expanded))
}
// Рендеринг дерева топиков
const renderTree = (topics: Topic[]): any => {
const renderTree = (topics: Topic[]): JSX.Element => {
return (
<For each={topics}>
{(topic) => {
@@ -253,8 +253,12 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
}}
style={{
'padding-left': `${(topic.level || 0) * 20}px`,
'cursor': 'pointer',
'border': isSelected ? '2px solid #007bff' : isTarget ? '2px dashed #28a745' : '1px solid transparent',
cursor: 'pointer',
border: isSelected
? '2px solid #007bff'
: isTarget
? '2px dashed #28a745'
: '1px solid transparent',
'background-color': isSelected ? '#e3f2fd' : isTarget ? '#d4edda' : 'transparent'
}}
>
@@ -276,7 +280,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
</button>
</Show>
<Show when={!hasChildren}>
<span style={{ width: '12px' }}></span>
<span style={{ width: '12px' }} />
</Show>
<Show when={isSelected}>
@@ -295,9 +299,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
</div>
<Show when={isExpanded && hasChildren}>
<div class={styles.treeChildren}>
{renderTree(topic.children!)}
</div>
<div class={styles.treeChildren}>{renderTree(topic.children!)}</div>
</Show>
</div>
)
@@ -306,23 +308,6 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
)
}
// Сброс корневого уровня (перетаскивание в корень)
const makeRootTopic = (topicId: number) => {
updateTopicParent(topicId, [])
const draggedTopic = findTopicById(topicId)
if (!draggedTopic) return
setChanges(prev => [
...prev.filter(c => c.topicId !== topicId),
{
topicId,
newParentIds: [],
oldParentIds: draggedTopic.parent_ids || []
}
])
}
// Сохранение изменений
const handleSave = () => {
if (changes().length === 0) {
@@ -338,12 +323,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
}
return (
<Modal
isOpen={props.isOpen}
onClose={props.onClose}
title="Управление иерархией тем"
size="large"
>
<Modal isOpen={props.isOpen} onClose={props.onClose} title="Управление иерархией тем" size="large">
<div class={styles.hierarchyContainer}>
<div class={styles.instructions}>
<h4>Инструкции:</h4>
@@ -382,15 +362,11 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
</div>
</Show>
<Show when={searchQuery() && !findTopicByTitle(searchQuery())}>
<div class={styles.searchNoResult}>
Тема не найдена
</div>
<div class={styles.searchNoResult}> Тема не найдена</div>
</Show>
</div>
<div class={styles.hierarchyTree}>
{renderTree(localTopics())}
</div>
<div class={styles.hierarchyTree}>{renderTree(localTopics())}</div>
<Show when={changes().length > 0}>
<div class={styles.changesSummary}>
@@ -400,11 +376,10 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
const topic = findTopicById(change.topicId)
return (
<div class={styles.changeItem}>
<strong>{topic?.title}</strong>: {
change.newParentIds.length === 0
? 'станет корневой темой'
: `переместится под тему #${change.newParentIds[change.newParentIds.length - 1]}`
}
<strong>{topic?.title}</strong>:{' '}
{change.newParentIds.length === 0
? 'станет корневой темой'
: `переместится под тему #${change.newParentIds[change.newParentIds.length - 1]}`}
</div>
)
}}
@@ -422,16 +397,10 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
</div>
<div class={styles.actionButtons}>
<button
class={styles.rootButton}
onClick={() => moveSelectedTopic(null)}
>
<button class={styles.rootButton} onClick={() => moveSelectedTopic(null)}>
🏠 Сделать корневой темой
</button>
<button
class={styles.cancelButton}
onClick={() => setSelectedForMove(null)}
>
<button class={styles.cancelButton} onClick={() => setSelectedForMove(null)}>
Отменить выбор
</button>
</div>
@@ -442,11 +411,7 @@ const TopicHierarchyModal: Component<TopicHierarchyModalProps> = (props) => {
<Button variant="secondary" onClick={props.onClose}>
Отмена
</Button>
<Button
variant="primary"
onClick={handleSave}
disabled={changes().length === 0}
>
<Button variant="primary" onClick={handleSave} disabled={changes().length === 0}>
Сохранить изменения ({changes().length})
</Button>
</div>

View File

@@ -1,8 +1,8 @@
import { Component, createSignal, For, Show } from 'solid-js'
import { MERGE_TOPICS_MUTATION } from '../graphql/mutations'
import styles from '../styles/Form.module.css'
import Button from '../ui/Button'
import Modal from '../ui/Modal'
import styles from '../styles/Form.module.css'
import { MERGE_TOPICS_MUTATION } from '../graphql/mutations'
// Типы для топиков
interface Topic {
@@ -44,10 +44,12 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
* Получает токен авторизации из localStorage или cookie
*/
const getAuthTokenFromCookie = () => {
return document.cookie
.split('; ')
.find(row => row.startsWith('auth_token='))
?.split('=')[1] || ''
return (
document.cookie
.split('; ')
.find((row) => row.startsWith('auth_token='))
?.split('=')[1] || ''
)
}
/**
@@ -55,9 +57,9 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
*/
const handleSourceTopicToggle = (topicId: number, checked: boolean) => {
if (checked) {
setSourceTopicIds(prev => [...prev, topicId])
setSourceTopicIds((prev) => [...prev, topicId])
} else {
setSourceTopicIds(prev => prev.filter(id => id !== topicId))
setSourceTopicIds((prev) => prev.filter((id) => id !== topicId))
}
}
@@ -78,13 +80,13 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
}
// Проверяем что все темы принадлежат одному сообществу
const targetTopic = props.topics.find(t => t.id === target)
const targetTopic = props.topics.find((t) => t.id === target)
if (!targetTopic) return false
const targetCommunity = targetTopic.community
const sourcesTopics = props.topics.filter(t => sources.includes(t.id))
const sourcesTopics = props.topics.filter((t) => sources.includes(t.id))
return sourcesTopics.every(topic => topic.community === targetCommunity)
return sourcesTopics.every((topic) => topic.community === targetCommunity)
}
/**
@@ -141,12 +143,12 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
}
const stats = mergeResult.stats as MergeStats
const statsText = stats ?
` (перенесено ${stats.followers_moved} подписчиков, ${stats.publications_moved} публикаций, ${stats.drafts_moved} черновиков, удалено ${stats.source_topics_deleted} тем)` : ''
const statsText = stats
? ` (перенесено ${stats.followers_moved} подписчиков, ${stats.publications_moved} публикаций, ${stats.drafts_moved} черновиков, удалено ${stats.source_topics_deleted} тем)`
: ''
props.onSuccess(mergeResult.message + statsText)
handleClose()
} catch (error) {
const errorMessage = (error as Error).message
setError(errorMessage)
@@ -173,7 +175,7 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
*/
const getAvailableTargetTopics = () => {
const sources = sourceTopicIds()
return props.topics.filter(topic => !sources.includes(topic.id))
return props.topics.filter((topic) => !sources.includes(topic.id))
}
/**
@@ -181,26 +183,22 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
*/
const getAvailableSourceTopics = () => {
const target = targetTopicId()
return props.topics.filter(topic => topic.id !== target)
return props.topics.filter((topic) => topic.id !== target)
}
return (
<Modal
isOpen={props.isOpen}
onClose={handleClose}
title="Слияние тем"
size="large"
>
<Modal isOpen={props.isOpen} onClose={handleClose} title="Слияние тем" size="large">
<div class={styles.form}>
<div class={styles.section}>
<h3 class={styles.sectionTitle}>Выбор целевой темы</h3>
<p class={styles.description}>
Выберите тему, в которую будут слиты остальные темы. Все подписчики и публикации будут перенесены в эту тему.
Выберите тему, в которую будут слиты остальные темы. Все подписчики и публикации будут
перенесены в эту тему.
</p>
<select
value={targetTopicId() || ''}
onChange={(e) => setTargetTopicId(e.target.value ? parseInt(e.target.value) : null)}
onChange={(e) => setTargetTopicId(e.target.value ? Number.parseInt(e.target.value) : null)}
class={styles.select}
disabled={loading()}
>
@@ -219,7 +217,8 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
<div class={styles.section}>
<h3 class={styles.sectionTitle}>Выбор исходных тем для слияния</h3>
<p class={styles.description}>
Выберите темы, которые будут слиты в целевую тему. Эти темы будут удалены после переноса всех связей.
Выберите темы, которые будут слиты в целевую тему. Эти темы будут удалены после переноса всех
связей.
</p>
<Show when={getAvailableSourceTopics().length > 0}>
@@ -242,7 +241,10 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
<div class={styles.topicInfo}>
{getCommunityName(topic.community)} ID: {topic.id}
{topic.stat && (
<span> {topic.stat.shouts} публ., {topic.stat.followers} подп.</span>
<span>
{' '}
{topic.stat.shouts} публ., {topic.stat.followers} подп.
</span>
)}
</div>
</div>
@@ -283,39 +285,32 @@ const TopicMergeModal: Component<TopicMergeModalProps> = (props) => {
<h4>Предпросмотр слияния:</h4>
<ul>
<li>
<strong>Целевая тема:</strong> {props.topics.find(t => t.id === targetTopicId())?.title}
<strong>Целевая тема:</strong> {props.topics.find((t) => t.id === targetTopicId())?.title}
</li>
<li>
<strong>Исходные темы:</strong> {sourceTopicIds().length} шт.
<ul>
<For each={sourceTopicIds()}>
{(id) => {
const topic = props.topics.find(t => t.id === id)
const topic = props.topics.find((t) => t.id === id)
return topic ? <li>{topic.title}</li> : null
}}
</For>
</ul>
</li>
<li>
<strong>Действие:</strong> Все подписчики, публикации и черновики будут перенесены в целевую тему, исходные темы будут удалены
<strong>Действие:</strong> Все подписчики, публикации и черновики будут перенесены в целевую
тему, исходные темы будут удалены
</li>
</ul>
</div>
</Show>
<div class={styles.modalActions}>
<Button
variant="secondary"
onClick={handleClose}
disabled={loading()}
>
<Button variant="secondary" onClick={handleClose} disabled={loading()}>
Отмена
</Button>
<Button
variant="danger"
onClick={handleMerge}
disabled={!canMerge() || loading()}
>
<Button variant="danger" onClick={handleMerge} disabled={!canMerge() || loading()}>
{loading() ? 'Выполняется слияние...' : 'Слить темы'}
</Button>
</div>

View File

@@ -1,7 +1,7 @@
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'
import styles from '../styles/Form.module.css'
interface Topic {
id: number
@@ -38,7 +38,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
const currentTopic = props.topic
if (!currentTopic) return []
return props.allTopics.filter(topic => {
return props.allTopics.filter((topic) => {
// Исключаем сам топик
if (topic.id === currentTopic.id) return false
@@ -58,7 +58,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
// Проверка, является ли топик потомком другого
const isDescendant = (ancestorId: number, descendantId: number): boolean => {
const descendant = props.allTopics.find(t => t.id === descendantId)
const descendant = props.allTopics.find((t) => t.id === descendantId)
if (!descendant || !descendant.parent_ids) return false
return descendant.parent_ids.includes(ancestorId)
@@ -66,7 +66,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
// Получение пути к корню для отображения полного пути
const getTopicPath = (topicId: number): string => {
const topic = props.allTopics.find(t => t.id === topicId)
const topic = props.allTopics.find((t) => t.id === topicId)
if (!topic) return ''
if (!topic.parent_ids || topic.parent_ids.length === 0) {
@@ -86,7 +86,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
let newParentIds: number[] = []
if (newParentId) {
const parentTopic = props.allTopics.find(t => t.id === newParentId)
const parentTopic = props.allTopics.find((t) => t.id === newParentId)
if (parentTopic) {
// Строим полный путь от корня до нового родителя
newParentIds = [...(parentTopic.parent_ids || []), newParentId]
@@ -128,10 +128,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
<div class={styles.currentSelection}>
<label class={styles.label}>Текущий родитель:</label>
<div class={styles.currentParent}>
<Show
when={getCurrentParentId()}
fallback={<span class={styles.noParent}>Корневая тема</span>}
>
<Show when={getCurrentParentId()} fallback={<span class={styles.noParent}>Корневая тема</span>}>
<span class={styles.parentPath}>
{getCurrentParentId() ? getTopicPath(getCurrentParentId()!) : ''}
</span>
@@ -153,9 +150,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
/>
<label for="root-option" class={styles.parentOptionLabel}>
<strong>🏠 Корневая тема</strong>
<div class={styles.parentDescription}>
Переместить на верхний уровень иерархии
</div>
<div class={styles.parentDescription}>Переместить на верхний уровень иерархии</div>
</label>
</div>
@@ -178,9 +173,7 @@ const TopicParentModal: Component<TopicParentModalProps> = (props) => {
<span class={styles.topicSlug}>{topic.slug}</span>
</div>
<Show when={topic.parent_ids && topic.parent_ids.length > 0}>
<div class={styles.parentPath}>
Путь: {getTopicPath(topic.id)}
</div>
<div class={styles.parentPath}>Путь: {getTopicPath(topic.id)}</div>
</Show>
</label>
</div>

View File

@@ -1,8 +1,8 @@
import { Component, createSignal, For, Show } from 'solid-js'
import { SET_TOPIC_PARENT_MUTATION } from '../graphql/mutations'
import styles from '../styles/Form.module.css'
import Button from '../ui/Button'
import Modal from '../ui/Modal'
import styles from '../styles/Form.module.css'
import { SET_TOPIC_PARENT_MUTATION } from '../graphql/mutations'
// Типы для топиков
interface Topic {
@@ -31,10 +31,12 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
* Получает токен авторизации
*/
const getAuthTokenFromCookie = () => {
return document.cookie
.split('; ')
.find(row => row.startsWith('auth_token='))
?.split('=')[1] || ''
return (
document.cookie
.split('; ')
.find((row) => row.startsWith('auth_token='))
?.split('=')[1] || ''
)
}
/**
@@ -51,7 +53,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
* Получает путь темы до корня
*/
const getTopicPath = (topicId: number): string => {
const topic = props.allTopics.find(t => t.id === topicId)
const topic = props.allTopics.find((t) => t.id === topicId)
if (!topic) return 'Неизвестная тема'
if (!topic.parent_ids || topic.parent_ids.length === 0) {
@@ -69,9 +71,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
if (parentId === childId) return true
const checkDescendants = (currentId: number): boolean => {
const descendants = props.allTopics.filter(t =>
t.parent_ids && t.parent_ids.includes(currentId)
)
const descendants = props.allTopics.filter((t) => t?.parent_ids?.includes(currentId))
for (const descendant of descendants) {
if (descendant.id === childId || checkDescendants(descendant.id)) {
@@ -92,7 +92,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
const query = searchQuery().toLowerCase()
return props.allTopics.filter(topic => {
return props.allTopics.filter((topic) => {
// Исключаем саму тему
if (topic.id === props.topic!.id) return false
@@ -149,7 +149,6 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
props.onSuccess(setResult.message)
handleClose()
} catch (error) {
const errorMessage = (error as Error).message
props.onError(`Ошибка назначения родителя: ${errorMessage}`)
@@ -169,12 +168,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
}
return (
<Modal
isOpen={props.isOpen}
onClose={handleClose}
title="Назначить родительскую тему"
size="medium"
>
<Modal isOpen={props.isOpen} onClose={handleClose} title="Назначить родительскую тему" size="medium">
<div class={styles.parentSelectorContainer}>
<Show when={props.topic}>
<div class={styles.currentSelection}>
@@ -186,10 +180,11 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
<div class={styles.currentParent}>
<strong>Текущее расположение:</strong>
<div class={styles.parentPath}>
{getCurrentParentId() ?
getTopicPath(props.topic!.id) :
{getCurrentParentId() ? (
getTopicPath(props.topic!.id)
) : (
<span class={styles.noParent}>🏠 Корневая тема</span>
}
)}
</div>
</div>
</div>
@@ -220,9 +215,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
disabled={loading()}
/>
<div class={styles.parentOptionLabel}>
<div class={styles.topicTitle}>
🏠 Сделать корневой темой
</div>
<div class={styles.topicTitle}>🏠 Сделать корневой темой</div>
<div class={styles.parentDescription}>
Тема будет перемещена на верхний уровень иерархии
</div>
@@ -244,9 +237,7 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
disabled={loading()}
/>
<div class={styles.parentOptionLabel}>
<div class={styles.topicTitle}>
{topic.title}
</div>
<div class={styles.topicTitle}>{topic.title}</div>
<div class={styles.parentDescription}>
<span class={styles.topicId}>ID: {topic.id}</span>
<span class={styles.topicSlug}> {topic.slug}</span>
@@ -261,10 +252,9 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
<Show when={getAvailableParents().length === 0}>
<div class={styles.noResults}>
{searchQuery() ?
'Не найдено подходящих тем по запросу' :
'Нет доступных родительских тем'
}
{searchQuery()
? 'Не найдено подходящих тем по запросу'
: 'Нет доступных родительских тем'}
</div>
</Show>
</div>
@@ -274,24 +264,21 @@ const TopicSimpleParentModal: Component<TopicSimpleParentModalProps> = (props) =
<div class={styles.preview}>
<h4>Предварительный просмотр:</h4>
<div class={styles.previewPath}>
<strong>Новое расположение:</strong><br />
<strong>Новое расположение:</strong>
<br />
{getTopicPath(selectedParentId()!)} <strong>{props.topic?.title}</strong>
</div>
</div>
</Show>
<div class={styles.modalActions}>
<Button
variant="secondary"
onClick={handleClose}
disabled={loading()}
>
<Button variant="secondary" onClick={handleClose} disabled={loading()}>
Отмена
</Button>
<Button
variant="primary"
onClick={handleSetParent}
disabled={loading() || (selectedParentId() === getCurrentParentId())}
disabled={loading() || selectedParentId() === getCurrentParentId()}
>
{loading() ? 'Назначение...' : 'Назначить родителя'}
</Button>