import { Box, Button, Paper, Typography, Menu, MenuItem, TextField, } from "@mui/material"; import { BackButton, createSightStore, editSightStore, languageStore, SelectArticleModal, TabPanel, SelectMediaDialog, UploadMediaDialog, Media, } from "@shared"; import { LanguageSwitcher, MediaArea, MediaAreaForSight, ReactMarkdownComponent, ReactMarkdownEditor, DeleteModal, } from "@widgets"; import { ImagePlus, Plus, Save, Trash2, Unlink, X } from "lucide-react"; import { observer } from "mobx-react-lite"; import { useState, useEffect } from "react"; import { MediaViewer } from "../../MediaViewer/index"; import { toast } from "react-toastify"; import { authInstance } from "@shared"; import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd"; type MediaItemShared = { id: string; filename: string; media_name?: string; media_type: number; }; export const CreateRightTab = observer( ({ value, index }: { value: number; index: number }) => { const [anchorEl, setAnchorEl] = useState(null); const { sight, createNewRightArticle, updateRightArticleInfo, linkPreviewMedia, unlinkPreviewMedia, createLinkWithRightArticle, deleteRightArticleMedia, unlinkRightAritcle, deleteRightArticle, linkExistingRightArticle, createSight, clearCreateSight, updateRightArticles, } = createSightStore; const { language } = languageStore; const { setFileToUpload, setUploadMediaOpen, uploadMediaOpen } = editSightStore; const [selectArticleDialogOpen, setSelectArticleDialogOpen] = useState(false); const [activeArticleIndex, setActiveArticleIndex] = useState( null ); const [type, setType] = useState<"article" | "media">("media"); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isSelectMediaDialogOpen, setIsSelectMediaDialogOpen] = useState(false); const [mediaTarget, setMediaTarget] = useState< "sightPreview" | "rightArticle" | null >(null); const [previewMedia, setPreviewMedia] = useState(null); useEffect(() => { if (sight.preview_media) { const fetchMedia = async () => { const response = await authInstance.get( `/media/${sight.preview_media}` ); setPreviewMedia(response.data); }; fetchMedia(); } }, [sight.preview_media]); useEffect(() => { if ( activeArticleIndex !== null && activeArticleIndex >= sight[language].right.length ) { setActiveArticleIndex(null); setType("media"); } }, [language, sight[language].right, activeArticleIndex]); const openMenu = Boolean(anchorEl); const handleClickMenu = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; const handleCloseMenu = () => { setAnchorEl(null); }; const handleSave = async () => { try { await createSight(language); toast.success("Достопримечательность успешно создана!"); clearCreateSight(); setActiveArticleIndex(null); setType("media"); } catch (error) { console.error("Failed to save sight:", error); toast.error("Ошибка при создании достопримечательности."); } }; const handleDisplayArticleFromList = (idx: number) => { setActiveArticleIndex(idx); setType("article"); }; const handleCreateNewLocalArticle = async () => { handleCloseMenu(); try { const newArticleId = await createNewRightArticle(); const newIndex = sight[language].right.findIndex( (a) => a.id === newArticleId ); if (newIndex > -1) { setActiveArticleIndex(newIndex); setType("article"); } else { setActiveArticleIndex(sight[language].right.length - 1); setType("article"); } } catch (error) { toast.error("Не удалось создать новую статью."); } }; const handleSelectExistingArticleAndLink = async ( selectedArticleId: number ) => { try { const linkedArticleId = await linkExistingRightArticle( selectedArticleId ); setSelectArticleDialogOpen(false); const newIndex = sight[language].right.findIndex( (a) => a.id === linkedArticleId ); if (newIndex > -1) { setActiveArticleIndex(newIndex); setType("article"); } } catch (error) { toast.error("Не удалось привязать существующую статью."); } }; const currentRightArticle = activeArticleIndex !== null && sight[language].right[activeArticleIndex] ? sight[language].right[activeArticleIndex] : null; const handleOpenUploadMedia = () => { setUploadMediaOpen(true); }; const handleOpenSelectMediaDialog = ( target: "sightPreview" | "rightArticle" ) => { setMediaTarget(target); setIsSelectMediaDialogOpen(true); }; const handleMediaSelectedFromDialog = async (media: MediaItemShared) => { setIsSelectMediaDialogOpen(false); if (mediaTarget === "sightPreview") { await linkPreviewMedia(media.id); } else if (mediaTarget === "rightArticle" && currentRightArticle) { await createLinkWithRightArticle(media, currentRightArticle.id); } setMediaTarget(null); }; const handleUnlinkPreviewMedia = async () => { await unlinkPreviewMedia(); setPreviewMedia(null); }; const handleMediaUploaded = async (media: MediaItemShared) => { setUploadMediaOpen(false); setFileToUpload(null); if (mediaTarget === "sightPreview") { linkPreviewMedia(media.id); } else if (mediaTarget === "rightArticle" && currentRightArticle) { await createLinkWithRightArticle(media, currentRightArticle.id); } setMediaTarget(null); }; const handleDragEnd = (result: any) => { const { source, destination } = result; if (!destination) return; const sourceIndex = source.index; const destinationIndex = destination.index; if (sourceIndex === destinationIndex) return; const newRightArticles = [...sight[language].right]; const [movedArticle] = newRightArticles.splice(sourceIndex, 1); newRightArticles.splice(destinationIndex, 0, movedArticle); updateRightArticles(newRightArticles); }; return (

{sight[language].name}

{ setType("media"); }} className={`w-full p-4 rounded-2xl cursor-pointer text-sm hover:bg-gray-300 transition-all duration-300 ${ type === "media" ? "bg-green-300 font-semibold" : "bg-green-200" }`} > Предпросмотр медиа {(provided) => ( {sight[language].right.length > 0 ? sight[language].right.map( (article, index) => ( {(provided, snapshot) => ( { handleDisplayArticleFromList( index ); setType("article"); }} > {article.heading} )} ) ) : null} {provided.placeholder} )} Создать новую { setSelectArticleDialogOpen(true); handleCloseMenu(); }} > Выбрать существующую статью {type === "article" && currentRightArticle ? ( activeArticleIndex !== null && updateRightArticleInfo( activeArticleIndex, language, e.target.value, currentRightArticle.body ) } variant="outlined" fullWidth /> activeArticleIndex !== null && updateRightArticleInfo( activeArticleIndex, language, currentRightArticle.heading, mdValue || "" ) } /> { if (files.length > 0) { setFileToUpload(files[0]); setMediaTarget("rightArticle"); handleOpenUploadMedia(); } }} deleteMedia={deleteRightArticleMedia} setSelectMediaDialogOpen={() => handleOpenSelectMediaDialog("rightArticle") } /> ) : type === "media" ? ( <> {type === "media" && ( {previewMedia && ( <> )} {!previewMedia && ( { linkPreviewMedia(mediaId); }} onFilesDrop={() => {}} contextObjectName={sight[language].name} contextType="sight" isArticle={false} /> )} )} ) : ( Выберите статью слева или секцию "Предпросмотр медиа" )} {type === "article" && activeArticleIndex !== null && ( {sight[language].right[activeArticleIndex].media.length > 0 ? ( ) : ( )} {sight[language].right[activeArticleIndex].heading || "Выберите статью"} {sight[language].right[activeArticleIndex].body ? ( ) : ( Предпросмотр статьи появится здесь )} {sight[language].right.length > 0 && sight[language].right.map((article, index) => ( ))} )}
setSelectArticleDialogOpen(false)} onSelectArticle={handleSelectExistingArticleAndLink} linkedArticleIds={sight[language].right.map((article) => article.id)} /> { setUploadMediaOpen(false); setFileToUpload(null); setMediaTarget(null); }} contextObjectName={sight[language].name} contextType="sight" isArticle={mediaTarget === "rightArticle"} articleName={ mediaTarget === "rightArticle" && activeArticleIndex !== null ? sight[language].right[activeArticleIndex].heading : undefined } afterUpload={handleMediaUploaded} /> { setIsSelectMediaDialogOpen(false); setMediaTarget(null); }} onSelectMedia={handleMediaSelectedFromDialog} /> { try { await deleteRightArticle(currentRightArticle?.id || 0); setActiveArticleIndex(null); setType("media"); toast.success("Статья удалена"); } catch { toast.error("Не удалось удалить статью"); } }} onCancel={() => setIsDeleteModalOpen(false)} />
); } );