// RightWidgetTab.tsx import { Box, Button, Paper, TextField, Typography } from "@mui/material"; import { TabPanel, BackButton, languageStore, // Предполагаем, что он есть в @shared Language, // Предполагаем, что он есть в @shared // SelectArticleModal, // Добавим позже // articlesStore, // Добавим позже } from "@shared"; import { LanguageSwitcher } from "@widgets"; // Предполагаем, что LanguageSwitcher у вас есть import { observer } from "mobx-react-lite"; import { useState, useMemo, useEffect } from "react"; import { editSightStore, BlockItem } from "@shared"; // Путь к вашему стору // Импортируем сюда же определения BlockItem, если не выносим в types.ts // export interface BlockItem { id: string; type: 'media' | 'article'; nameForSidebar: string; linkedArticleStoreId?: string; } // --- Начальные данные для структуры блоков (позже это может загружаться) --- // ID здесь должны быть уникальными для списка. const initialBlockStructures: Omit[] = [ { id: "preview_media_main", type: "media" }, { id: "article_1_local", type: "article" }, // Эти статьи будут редактироваться локально { id: "article_2_local", type: "article" }, ]; interface RightWidgetTabProps { value: number; index: number; } export const RightWidgetTab = observer( ({ value, index }: RightWidgetTabProps) => { const { language } = languageStore; // Текущий язык const { sightInfo } = editSightStore; // Данные достопримечательности // 1. Структура блоков: порядок, тип, связи (не сам контент) // Имена nameForSidebar будут динамически браться из sightInfo или articlesStore const [blockItemsStructure, setBlockItemsStructure] = useState< Omit[] >(initialBlockStructures); // 2. ID выбранного блока для редактирования const [selectedBlockId, setSelectedBlockId] = useState( () => { // По умолчанию выбираем первый блок, если он есть return initialBlockStructures.length > 0 ? initialBlockStructures[0].id : null; } ); // 3. Состояние для модального окна выбора существующей статьи (добавим позже) // const [isSelectModalOpen, setIsSelectModalOpen] = useState(false); // --- Производные данные (Derived State) --- // Блоки для отображения в сайдбаре (с локализованными именами) const blocksForSidebar: BlockItem[] = useMemo(() => { return blockItemsStructure.map((struct) => { let name = `Блок ${struct.id}`; // Имя по умолчанию if (struct.type === "media" && struct.id === "preview_media_main") { name = "Превью-медиа"; // Фиксированное имя для этого блока } else if (struct.type === "article") { if (struct.linkedArticleStoreId) { // TODO: Найти имя в articlesStore по struct.linkedArticleStoreId name = `Связанная: ${struct.linkedArticleStoreId}`; } else { // Это локальная статья, берем заголовок из editSightStore const articleContent = sightInfo[language]?.right?.find( (a) => a.id === struct.id ); name = articleContent?.heading || `Статья ${struct.id.slice(-4)} (${language.toUpperCase()})`; } } return { ...struct, nameForSidebar: name }; }); }, [blockItemsStructure, language, sightInfo]); // Данные выбранного блока (структура + контент) const selectedBlockData = useMemo(() => { if (!selectedBlockId) return null; const structure = blockItemsStructure.find( (b) => b.id === selectedBlockId ); if (!structure) return null; if (structure.type === "article" && !structure.linkedArticleStoreId) { const content = sightInfo[language]?.right?.find( (a) => a.id === selectedBlockId ); return { structure, content: content || { id: selectedBlockId, heading: "", body: "" }, // Заглушка, если нет контента }; } // Для media или связанных статей пока просто структура return { structure, content: null }; }, [selectedBlockId, blockItemsStructure, language, sightInfo]); // --- Обработчики событий --- const handleSelectBlock = (blockId: string) => { setSelectedBlockId(blockId); }; const handleCreateNewArticle = () => { const newBlockId = `article_local_${Date.now()}`; const newBlockStructure: Omit = { id: newBlockId, type: "article", }; setBlockItemsStructure((prev) => [...prev, newBlockStructure]); // Добавляем пустой контент для этой статьи во все языки в editSightStore const baseName = `Новая статья ${ blockItemsStructure.filter((b) => b.type === "article").length + 1 }`; ["ru", "en", "zh"].forEach((lang) => { const currentLang = lang as Language; if ( editSightStore.sightInfo[currentLang] && !editSightStore.sightInfo[currentLang].right?.find( (r) => r.id === newBlockId ) ) { editSightStore.sightInfo[currentLang].right.push({ id: newBlockId, heading: `${baseName} (${currentLang.toUpperCase()})`, body: `Содержимое для ${baseName} (${currentLang.toUpperCase()})...`, }); } }); setSelectedBlockId(newBlockId); }; const handleHeadingChange = (newHeading: string) => { if ( selectedBlockData && selectedBlockData.structure.type === "article" && !selectedBlockData.structure.linkedArticleStoreId ) { const blockId = selectedBlockData.structure.id; const langData = editSightStore.sightInfo[language]; const article = langData?.right?.find((a) => a.id === blockId); if (article) { article.heading = newHeading; } else if (langData) { // Если статьи еще нет, добавляем langData.right.push({ id: blockId, heading: newHeading, body: "" }); } // Обновить имя в сайдбаре (т.к. blocksForSidebar пересчитается) // Для этого достаточно, чтобы sightInfo был observable и blocksForSidebar от него зависел } }; const handleBodyChange = (newBody: string) => { if ( selectedBlockData && selectedBlockData.structure.type === "article" && !selectedBlockData.structure.linkedArticleStoreId ) { const blockId = selectedBlockData.structure.id; const langData = editSightStore.sightInfo[language]; const article = langData?.right?.find((a) => a.id === blockId); if (article) { article.body = newBody; } else if (langData) { // Если статьи еще нет, добавляем langData.right.push({ id: blockId, heading: "", body: newBody }); } } }; const handleDeleteBlock = (blockIdToDelete: string) => { setBlockItemsStructure((prev) => prev.filter((b) => b.id !== blockIdToDelete) ); // Удаляем контент из editSightStore для всех языков ["ru", "en", "zh"].forEach((lang) => { const currentLang = lang as Language; if (editSightStore.sightInfo[currentLang]) { editSightStore.sightInfo[currentLang].right = editSightStore.sightInfo[currentLang].right?.filter( (r) => r.id !== blockIdToDelete ); } }); if (selectedBlockId === blockIdToDelete) { setSelectedBlockId( blockItemsStructure.length > 1 ? blockItemsStructure.filter((b) => b.id !== blockIdToDelete)[0]?.id : null ); } }; const handleSave = () => { console.log( "Сохранение Right Widget:", JSON.stringify(editSightStore.sightInfo, null, 2) ); // Здесь будет логика отправки editSightStore.sightInfo на сервер alert("Данные для сохранения (см. консоль)"); }; // --- Инициализация контента в сторе для initialBlockStructures (если его там нет) --- useEffect(() => { initialBlockStructures.forEach((struct) => { if (struct.type === "article" && !struct.linkedArticleStoreId) { const baseName = `Статья ${struct.id.split("_")[1]}`; // Пример "История" или "Факты" ["ru", "en", "zh"].forEach((lang) => { const currentLang = lang as Language; if ( editSightStore.sightInfo[currentLang] && !editSightStore.sightInfo[currentLang].right?.find( (r) => r.id === struct.id ) ) { editSightStore.sightInfo[currentLang].right?.push({ id: struct.id, heading: `${baseName} (${currentLang.toUpperCase()})`, // Например: "История (RU)" body: `Начальное содержимое для ${baseName} на ${currentLang.toUpperCase()}.`, }); } }); } }); }, []); // Запускается один раз при монтировании return ( {/* Компонент сайдбара списка блоков */} Блоки {blocksForSidebar.map((block) => ( ))} {/* TODO: Кнопка "Выбрать существующую" */} {/* Компонент редактора выбранного блока */} Редактор блока ({language.toUpperCase()}) {selectedBlockData ? ( ID: {selectedBlockData.structure.id} Тип: {selectedBlockData.structure.type} {selectedBlockData.structure.type === "media" && ( Загрузчик медиа для "{selectedBlockData.structure.id}" )} {selectedBlockData.structure.type === "article" && !selectedBlockData.structure.linkedArticleStoreId && selectedBlockData.content && ( handleHeadingChange(e.target.value)} sx={{ mb: 2 }} /> handleBodyChange(e.target.value)} sx={{ mb: 2 }} // Здесь позже можно будет вставить SightEdit /> {/* TODO: Секция медиа для статьи */} )} {selectedBlockData.structure.type === "article" && selectedBlockData.structure.linkedArticleStoreId && ( Это связанная статья:{" "} {selectedBlockData.structure.linkedArticleStoreId} {/* TODO: Кнопки "Открепить", "Удалить из списка" */} )} ) : ( Выберите блок для редактирования )} {/* */} ); } );