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 (
{value === index && {children}}
);
}
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}`}
);
});