import { Typography, Button, Box, Accordion, AccordionSummary, AccordionDetails, useTheme, TextField, } from "@mui/material"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { axiosInstance } from "../providers/data"; import { useForm, Controller } from "react-hook-form"; import { MarkdownEditor } from "./MarkdownEditor"; import React, { useState, useCallback, useEffect } from "react"; import { useDropzone } from "react-dropzone"; import { ALLOWED_IMAGE_TYPES, ALLOWED_VIDEO_TYPES, } from "../components/media/MediaFormUtils"; import { EVERY_LANGUAGE, Languages } from "@stores"; import { useNotification } from "@refinedev/core"; const MemoizedSimpleMDE = React.memo(MarkdownEditor); type MediaFile = { file: File; preview: string; uploading: boolean; mediaId?: number; }; type Props = { parentId?: string | number; parentResource: string; childResource: string; title: string; left?: boolean; language: Languages; setHeadingParent?: (heading: string) => void; setBodyParent?: (body: string) => void; onSave?: (something: any) => void; noReset?: boolean; }; export const CreateSightArticle = ({ parentId, parentResource, childResource, title, left, language, setHeadingParent, setBodyParent, onSave, noReset, }: Props) => { const notification = useNotification(); const theme = useTheme(); const [mediaFiles, setMediaFiles] = useState([]); const [workingLanguage, setWorkingLanguage] = useState(language); const { register: registerItem, watch, control: controlItem, handleSubmit: handleSubmitItem, reset: resetItem, setValue, formState: { errors: itemErrors }, } = useForm({ defaultValues: { heading: "", body: "", }, }); const [articleData, setArticleData] = useState({ heading: EVERY_LANGUAGE(""), body: EVERY_LANGUAGE(""), }); function updateTranslations() { const newArticleData = { ...articleData, heading: { ...articleData.heading, [workingLanguage]: watch("heading") ?? "", }, body: { ...articleData.body, [workingLanguage]: watch("body") ?? "", }, }; setArticleData(newArticleData); return newArticleData; } useEffect(() => { setValue("heading", articleData.heading[workingLanguage] ?? ""); setValue("body", articleData.body[workingLanguage] ?? ""); }, [workingLanguage, articleData, setValue]); useEffect(() => { updateTranslations(); setWorkingLanguage(language); }, [language]); useEffect(() => { setHeadingParent?.(watch("heading")); setBodyParent?.(watch("body")); }, [watch("heading"), watch("body"), setHeadingParent, setBodyParent]); const simpleMDEOptions = React.useMemo( () => ({ placeholder: "Введите контент в формате Markdown...", spellChecker: false, }), [] ); const onDrop = useCallback((acceptedFiles: File[]) => { const newFiles = acceptedFiles.map((file) => ({ file, preview: URL.createObjectURL(file), uploading: false, })); setMediaFiles((prev) => [...prev, ...newFiles]); }, []); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, accept: { "image/jpeg": [".jpeg", ".jpg"], "image/png": [".png"], "image/webp": [".webp"], "video/mp4": [".mp4"], "video/webm": [".webm"], "video/ogg": [".ogg"], }, multiple: true, }); const uploadMedia = async (mediaFile: MediaFile) => { const formData = new FormData(); formData.append("media_name", mediaFile.file.name); formData.append("filename", mediaFile.file.name); formData.append( "type", mediaFile.file.type.startsWith("image/") ? "1" : "2" ); formData.append("file", mediaFile.file); const response = await axiosInstance.post( `${import.meta.env.VITE_KRBL_API}/media`, formData ); return response.data.id; }; const handleCreate = async (data: { heading: string; body: string }) => { try { // Создаем статью const response = await axiosInstance.post( `${import.meta.env.VITE_KRBL_API}/${childResource}`, { ...data, translations: updateTranslations(), } ); const itemId = response.data.id; if (parentId) { // Получаем существующие статьи для определения порядкового номера const existingItemsResponse = await axiosInstance.get( `${ import.meta.env.VITE_KRBL_API }/${parentResource}/${parentId}/${childResource}` ); const existingItems = existingItemsResponse.data ?? []; const nextPageNum = existingItems.length + 1; if (!left) { await axiosInstance.post( `${ import.meta.env.VITE_KRBL_API }/${parentResource}/${parentId}/${childResource}/`, { [`${childResource}_id`]: itemId, page_num: nextPageNum, } ); } else { const response = await axiosInstance.get( `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/` ); const data = response.data; if (data) { await axiosInstance.patch( `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/`, { ...data, left_article: itemId, } ); } } } // Загружаем все медиа файлы и получаем их ID const mediaIds = await Promise.all( mediaFiles.map(async (mediaFile) => { return await uploadMedia(mediaFile); }) ); // Привязываем все медиа к статье await Promise.all( mediaIds.map((mediaId, index) => axiosInstance.post( `${import.meta.env.VITE_KRBL_API}/article/${itemId}/media/`, { media_id: mediaId, media_order: index + 1, } ) ) ); if (noReset) { setValue("heading", ""); setValue("body", ""); } else { resetItem(); } if (onSave) { onSave(response.data); if (notification && typeof notification.open === "function") { notification.open({ message: "Статья успешно создана", type: "success", }); } } else { window.location.reload(); } } catch (err: any) { console.error("Error creating item:", err); } }; const removeMedia = (index: number) => { setMediaFiles((prev) => { const newFiles = [...prev]; URL.revokeObjectURL(newFiles[index].preview); newFiles.splice(index, 1); return newFiles; }); }; return ( ( )} /> {/* Dropzone для медиа файлов */} {isDragActive ? "Перетащите файлы сюда..." : "Перетащите файлы сюда или кликните для выбора"} {/* Превью загруженных файлов */} {mediaFiles.map((mediaFile, index) => ( {mediaFile.file.type.startsWith("image/") ? ( {mediaFile.file.name} ) : ( {mediaFile.file.name} )} ))} ); };