import { Autocomplete, Box, TextField, Paper, Typography, Tab, Tabs, Button, Stack, } from "@mui/material"; import { Edit, useAutocomplete } from "@refinedev/mui"; import { useForm } from "@refinedev/react-hook-form"; import { Controller, FieldValues } from "react-hook-form"; import { Link, useParams } from "react-router"; import React, { useState, useEffect } from "react"; import { CreateSightArticle, LinkedItemsContents } from "@components"; import { ArticleItem, articleFields } from "./types"; import { axiosInstance, TOKEN_KEY } from "@providers"; import { observer } from "mobx-react-lite"; import { Languages, languageStore, articleStore, META_LANGUAGE, EVERY_LANGUAGE } from "@stores"; import axios from "axios"; import { LanguageSelector, MediaData, MediaView } from "@ui"; import { ArticleEditModal } from "../../components/modals/ArticleEditModal/index"; function a11yProps(index: number) { return { id: `simple-tab-${index}`, "aria-controls": `simple-tabpanel-${index}`, }; } interface TabPanelProps { children?: React.ReactNode; index: number; value: number; } function CustomTabPanel(props: TabPanelProps) { const { children, value, index, ...other } = props; return ( ); } export const SightEdit = observer(() => { const { id: sightId } = useParams<{ id: string }>(); const { language, setLanguageAction } = languageStore; const [previewSelected, setPreviewSelected] = useState(true); const { setArticleModalOpenAction, setArticleIdAction } = articleStore; const [sightData, setSightData] = useState({ name: EVERY_LANGUAGE(""), address: EVERY_LANGUAGE("") }); const { saveButtonProps, register, refineCore: {onFinish}, control, watch, getValues, setValue, handleSubmit, formState: { errors }, } = useForm({ refineCoreProps: META_LANGUAGE(language), warnWhenUnsavedChanges: false }); const getMedia = async (id?: string | number) => { if(!id) return; try { const response = await axios.get( `${import.meta.env.VITE_KRBL_API}/article/${id}/media`, { headers: { Authorization: `Bearer ${localStorage.getItem(TOKEN_KEY)}`, "Accept-Language": language, }, } ); return response.data[0]; } catch { return; } }; useEffect(() => { setLanguageAction("ru"); }, []); const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({ resource: "city", onSearch: (value) => [ { field: "name", operator: "contains", value, }, ], ...META_LANGUAGE("ru") }); const [mediaFile, setMediaFile] = useState(); const [leftArticleData, setLeftArticleData] = useState<{ heading: string; body: string; media: MediaData; }>(); const [tabValue, setTabValue] = useState(0); const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({ resource: "media", onSearch: (value) => [ { field: "media_name", operator: "contains", value, }, ] }); const { autocompleteProps: articleAutocompleteProps } = useAutocomplete({ resource: "article", onSearch: (value) => [ { field: "heading", operator: "contains", value, }, { field: "media_type", operator: "contains", value, }, ], }); useEffect(() => { if(sightData.name[language]) setValue("name", sightData.name[language]); if(sightData.address[language]) setValue("address", sightData.address[language]); }, [language, sightData, setValue]); useEffect(() => { const latitude = getValues("latitude"); const longitude = getValues("longitude"); if (latitude && longitude) { setCoordinatesPreview({ latitude: latitude, longitude: longitude, }); } }, [getValues]); const handleCoordinatesChange = (e: React.ChangeEvent) => { const [lat, lon] = e.target.value.split(",").map((s) => s.trim()); setCoordinatesPreview({ latitude: lat, longitude: lon, }); setValue("latitude", lat); setValue("longitude", lon); }; // Состояния для предпросмотра const [creatingArticleHeading, setCreatingArticleHeading] = useState(""); const [creatingArticleBody, setCreatingArticleBody] = useState(""); const [coordinatesPreview, setCoordinatesPreview] = useState({ latitude: "", longitude: "", }); const [selectedArticleIndex, setSelectedArticleIndex] = useState(-1); const [thumbnailPreview, setThumbnailPreview] = useState(null); const [watermarkLUPreview, setWatermarkLUPreview] = useState( null ); const [watermarkRDPreview, setWatermarkRDPreview] = useState( null ); const [linkedArticles, setLinkedArticles] = useState([]); // Следим за изменениями во всех полях const selectedArticle = linkedArticles[selectedArticleIndex]; const previewMediaId = watch("preview_media"); const leftArticleId = watch("left_article"); useEffect(() => { if (previewMediaId) { const selectedMedia = mediaAutocompleteProps.options.find( (option) => option.id === previewMediaId ); console.log("Triggering", previewMediaId) if(!selectedMedia) return; setMediaFile(selectedMedia); } }, [previewMediaId, mediaAutocompleteProps.options]); // useEffect(() => { // const selectedWatermarkLU = mediaAutocompleteProps.options.find( // (option) => option.id === watermarkLUContent // ); // setWatermarkLUPreview( // selectedWatermarkLU // ? `${import.meta.env.VITE_KRBL_MEDIA}${ // selectedWatermarkLU.id // }/download?token=${localStorage.getItem(TOKEN_KEY)}` // : null // ); // }, [watermarkLUContent, ]); const addressContent = watch("address"); const latitudeContent = watch("latitude"); const longitudeContent = watch("longitude"); const thumbnailContent = watch("thumbnail"); const watermarkLUContent = watch("watermark_lu"); const watermarkRDContent = watch("watermark_rd"); useEffect(() => { setCoordinatesPreview({ latitude: latitudeContent ?? "", longitude: longitudeContent ?? "", }); }, [latitudeContent, longitudeContent]); useEffect(() => { if(linkedArticles[selectedArticleIndex]?.id) { getMedia(linkedArticles[selectedArticleIndex].id).then((media) => { setMediaFile(media); }); }; }, [selectedArticleIndex, linkedArticles]); useEffect(() => { const selectedThumbnail = mediaAutocompleteProps.options.find( (option) => option.id === thumbnailContent ); setThumbnailPreview( selectedThumbnail ? `${import.meta.env.VITE_KRBL_MEDIA}${ selectedThumbnail.id }/download?token=${localStorage.getItem(TOKEN_KEY)}` : null ); }, [thumbnailContent, mediaAutocompleteProps.options]); useEffect(() => { const selectedWatermarkLU = mediaAutocompleteProps.options.find( (option) => option.id === watermarkLUContent ); setWatermarkLUPreview( selectedWatermarkLU ? `${import.meta.env.VITE_KRBL_MEDIA}${ selectedWatermarkLU.id }/download?token=${localStorage.getItem(TOKEN_KEY)}` : null ); }, [watermarkLUContent, mediaAutocompleteProps.options]); useEffect(() => { const selectedWatermarkRD = mediaAutocompleteProps.options.find( (option) => option.id === watermarkRDContent ); setWatermarkRDPreview( selectedWatermarkRD ? `${import.meta.env.VITE_KRBL_MEDIA}${ selectedWatermarkRD.id }/download?token=${localStorage.getItem(TOKEN_KEY)}` : null ); }, [watermarkRDContent, mediaAutocompleteProps.options]); useEffect(() => { const selectedLeftArticle = articleAutocompleteProps.options.find( (option) => option.id === leftArticleId ); if (!selectedLeftArticle?.id) return; getMedia(selectedLeftArticle.id).then((media) => { setLeftArticleData({ heading: selectedLeftArticle.heading, body: selectedLeftArticle.body, media, }); }); }, [leftArticleId, articleAutocompleteProps.loading]); function updateTranslations(update: boolean = true) { const newSightData = { ...sightData, name: { ...sightData.name, [language]: watch("name") ?? "", }, address: { ...sightData.address, [language]: watch("address") ?? "", } } if(update) setSightData(newSightData); return newSightData; } const handleLanguageChange = (lang: Languages) => { updateTranslations(); setLanguageAction(lang); }; const handleFormSubmit = handleSubmit(async (values: FieldValues) => { const newTranslations = updateTranslations(false); console.log(newTranslations); await onFinish({ ...values, translations: newTranslations }); }); useEffect(() => { return () => { setLanguageAction("ru"); }; }, [setLanguageAction]); const [articleAdditionMode, setArticleAdditionMode] = useState<'attaching' | 'creating'>('attaching'); const [selectedItemId, setSelectedItemId] = useState(); const [updatedLinkedArticles, setUpdatedLinkedArticles] = useState([]); const linkItem = () => { if (!selectedItemId) return; const requestData = { article_id: selectedItemId, page_num: linkedArticles.length+1, } axiosInstance .post(`${import.meta.env.VITE_KRBL_API}/sight/${sightId}/article`, requestData) .then(() => { axiosInstance.get(`${import.meta.env.VITE_KRBL_API}/sight/${sightId}/article`) .then((response) => { setUpdatedLinkedArticles(response?.data || []); setSelectedItemId(undefined); }); }) .catch((error) => { console.error("Error linking item:", error); }); }; return ( setTabValue(newValue)} aria-label="basic tabs example" > {/* Форма редактирования */} ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( { //setPreviewSelected(true); //setSelectedMediaIndex(-1); }} label="Медиа-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} /> )} /> )} /> (
)} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) && option.media_type === 3 ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter((option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter((option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); setLeftArticleData(undefined); }} getOptionLabel={(item) => { return item ? item.heading : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter((option) => option.heading .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( )} /> )} /> {leftArticleId ? ( ) : ( <> Создать и прикрепить новую статью: { //console.log("Updating", heading) setCreatingArticleHeading(heading); }} setBodyParent={(body) => { setCreatingArticleBody(body); }} /> // // // )} {leftArticleData?.media && ( )} {/* Заголовок статьи */} theme.palette.mode === "dark" ? "grey.300" : "grey.800", mb: 3, }} > {leftArticleId ? leftArticleData?.heading : creatingArticleHeading} {/* Адрес */} Адрес:{" "} theme.palette.mode === "dark" ? "grey.300" : "grey.800", }} > {addressContent} {/* Текст статьи */} theme.palette.mode === "dark" ? "grey.300" : "grey.800", }} > {leftArticleId ? leftArticleData?.body : creatingArticleBody} ( option.id === field.value ) || null } onChange={(_, value) => { console.log(value, _) field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) && [1,2,5,6].includes(option.media_type) ); }} renderInput={(params) => ( { //setPreviewSelected(true); //setSelectedMediaIndex(-1); }} label="Медиа-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} /> )} /> )} /> setArticleAdditionMode("attaching")} > Добавить существующую статью setArticleAdditionMode("creating")} > Создать и привязать новую статью {articleAdditionMode === "attaching" && ( option.id === selectedItemId ) || null } onChange={(_, value) => { setSelectedItemId(value?.id || ""); setLeftArticleData(undefined); }} getOptionLabel={(item) => { return item ? item.heading : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter((option) => option.heading .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( )} /> )} {articleAdditionMode === "creating" && ( { console.log("Updating", heading) setCreatingArticleHeading(heading); }} setBodyParent={(body) => { setCreatingArticleBody(body); }} /> )} Привязанные статьи type="edit" disableCreation parentId={sightId!} dragAllowed={true} setItemsParent={setLinkedArticles} parentResource="sight" fields={articleFields} childResource="article" title="статьи" updatedLinkedItems={updatedLinkedArticles} /> {/* Предпросмотр */} {mediaFile && ( )} { {!previewSelected && articleAdditionMode !== "creating" && ( {selectedArticle && ( {selectedArticle.heading} )} {selectedArticle && ( {selectedArticle.body} )} )} {articleAdditionMode === "creating" && ( {creatingArticleHeading} {creatingArticleBody} )} {linkedArticles.map((article, index) => ( { setSelectedArticleIndex(index); setPreviewSelected(false); }} sx={{ cursor: "pointer", bgcolor: "transparent", color: "inherit", textDecoration: selectedArticleIndex === index ? "underline" : "none", p: 1, borderRadius: 1, }} > {article.heading} ))} } ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.name : ""; }} isOptionEqualToValue={(option, value) => { console.log(cityAutocompleteProps.options) return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter((option) => option.name .toLowerCase() .includes(inputValue.toLowerCase()) ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) && option.media_type === 3 ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) && option.media_type === 4 ); }} renderInput={(params) => ( )} /> )} /> ( option.id === field.value ) || null } onChange={(_, value) => { field.onChange(value?.id || ""); }} getOptionLabel={(item) => { return item ? item.media_name : ""; }} isOptionEqualToValue={(option, value) => { return option.id === value?.id; }} filterOptions={(options, { inputValue }) => { return options.filter( (option) => option.media_name .toLowerCase() .includes(inputValue.toLowerCase()) && option.media_type === 4 ); }} renderInput={(params) => ( )} /> )} /> {/* Предпросмотр */} theme.palette.mode === "dark" ? "background.paper" : "#fff", }} > Предпросмотр {thumbnailPreview && ( Адрес:{" "} theme.palette.mode === "dark" ? "grey.300" : "grey.800", }} > {`${addressContent}`} Логотип достопримечательности: )} {/* Водяные знаки */} Водяные знаки: {watermarkLUPreview && ( Левый верхний: )} {watermarkRDPreview && ( Правый верхний: )} {/* Координаты */} Координаты:{" "} theme.palette.mode === "dark" ? "grey.300" : "grey.800", }} > {`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`} ); });