feat: fix sight edit
This commit is contained in:
@@ -202,87 +202,100 @@ export const SelectArticleModal = observer(
|
||||
)}
|
||||
</List>
|
||||
</Paper>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
width: "100%",
|
||||
minWidth: 320,
|
||||
maxWidth: 310,
|
||||
|
||||
background:
|
||||
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
|
||||
|
||||
padding: 0,
|
||||
margin: "0px auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
<Box className="max-h-[80%] overflow-y-scroll mx-auto rounded-[10px]">
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 175,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "3px",
|
||||
}}
|
||||
>
|
||||
{articlesStore.articleMedia ? (
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: articlesStore.articleMedia.id,
|
||||
media_type: articlesStore.articleMedia.media_type,
|
||||
filename: articlesStore.articleMedia.filename,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ImagePlus size={48} color="white" />
|
||||
)}
|
||||
</Box>
|
||||
minWidth: 320,
|
||||
maxWidth: 310,
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
background:
|
||||
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
|
||||
color: "white",
|
||||
margin: "5px 0px 5px 0px",
|
||||
|
||||
padding: 0,
|
||||
margin: "0px auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 1,
|
||||
padding: 1,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h5"
|
||||
component="h2"
|
||||
sx={{
|
||||
wordBreak: "break-word",
|
||||
fontSize: "24px",
|
||||
fontWeight: 700,
|
||||
lineHeight: "120%",
|
||||
}}
|
||||
>
|
||||
{articlesStore.articleData?.heading || "Название cтатьи"}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{articlesStore.articleData?.body && (
|
||||
<Box
|
||||
sx={{
|
||||
padding: 1,
|
||||
maxHeight: "200px",
|
||||
overflowY: "scroll",
|
||||
background:
|
||||
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
minHeight: 100,
|
||||
padding: "3px",
|
||||
display: "flex",
|
||||
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
|
||||
"& img": {
|
||||
borderTopLeftRadius: "10px",
|
||||
borderTopRightRadius: "10px",
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
objectFit: "contain",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ReactMarkdownComponent
|
||||
value={articlesStore.articleData?.body || "Описание"}
|
||||
/>
|
||||
{articlesStore.articleMedia ? (
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: articlesStore.articleMedia.id,
|
||||
media_type: articlesStore.articleMedia.media_type,
|
||||
filename: articlesStore.articleMedia.filename,
|
||||
}}
|
||||
fullWidth={true}
|
||||
/>
|
||||
) : (
|
||||
<ImagePlus size={48} color="white" />
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
background:
|
||||
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
|
||||
color: "white",
|
||||
margin: "5px 0px 5px 0px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 1,
|
||||
padding: 1,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h5"
|
||||
component="h2"
|
||||
sx={{
|
||||
wordBreak: "break-word",
|
||||
fontSize: "24px",
|
||||
fontWeight: 700,
|
||||
lineHeight: "120%",
|
||||
}}
|
||||
>
|
||||
{articlesStore.articleData?.heading || "Название cтатьи"}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{articlesStore.articleData?.body && (
|
||||
<Box
|
||||
sx={{
|
||||
padding: 1,
|
||||
maxHeight: "200px",
|
||||
overflowY: "scroll",
|
||||
background:
|
||||
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
|
||||
}}
|
||||
>
|
||||
<ReactMarkdownComponent
|
||||
value={articlesStore.articleData?.body || "Описание"}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ p: 2 }}>
|
||||
<Button onClick={onClose}>Отмена</Button>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MEDIA_TYPE_LABELS, editSightStore } from "@shared";
|
||||
import { MEDIA_TYPE_LABELS, MEDIA_TYPE_VALUES, editSightStore } from "@shared";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
@@ -31,6 +31,7 @@ interface UploadMediaDialogProps {
|
||||
media_type: number;
|
||||
}) => void;
|
||||
afterUploadSight?: (id: string) => void;
|
||||
hardcodeType?: "thumbnail" | "watermark_lu" | "watermark_rd" | null;
|
||||
}
|
||||
|
||||
export const UploadMediaDialog = observer(
|
||||
@@ -39,6 +40,7 @@ export const UploadMediaDialog = observer(
|
||||
onClose,
|
||||
afterUpload,
|
||||
afterUploadSight,
|
||||
hardcodeType,
|
||||
}: UploadMediaDialogProps) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -165,10 +167,12 @@ export const UploadMediaDialog = observer(
|
||||
<FormControl fullWidth sx={{ width: "50%" }}>
|
||||
<InputLabel>Тип медиа</InputLabel>
|
||||
<Select
|
||||
value={mediaType}
|
||||
value={
|
||||
hardcodeType ? MEDIA_TYPE_VALUES[hardcodeType] : mediaType
|
||||
}
|
||||
disabled={!!hardcodeType}
|
||||
label="Тип медиа"
|
||||
onChange={(e) => setMediaType(Number(e.target.value))}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{availableMediaTypes.map((type) => (
|
||||
<MenuItem key={type} value={type}>
|
||||
|
||||
@@ -98,18 +98,22 @@ class CreateSightStore {
|
||||
heading: "New Heading (EN)",
|
||||
body: "New Text (EN)",
|
||||
};
|
||||
const articleZhData = { heading: "新标题 (ZH)", body: "新文本 (ZH)" };
|
||||
const articleZhData = {
|
||||
heading: "Новый заголовок (ZH)",
|
||||
body: "Новый текст (ZH)",
|
||||
};
|
||||
|
||||
try {
|
||||
const articleRes = await languageInstance("ru").post(
|
||||
"/article",
|
||||
articleRuData
|
||||
);
|
||||
this.needLeaveAgree = true;
|
||||
const articleRes = await authInstance.post("/article", {
|
||||
translation: {
|
||||
ru: articleRuData,
|
||||
en: articleEnData,
|
||||
zh: articleZhData,
|
||||
},
|
||||
});
|
||||
const { id } = articleRes.data; // New article's ID
|
||||
|
||||
await languageInstance("en").patch(`/article/${id}`, articleEnData);
|
||||
await languageInstance("zh").patch(`/article/${id}`, articleZhData);
|
||||
|
||||
runInAction(() => {
|
||||
const newArticleEntry = { id, media: [] };
|
||||
this.sight.ru.right.push({ ...newArticleEntry, ...articleRuData });
|
||||
@@ -376,6 +380,7 @@ class CreateSightStore {
|
||||
|
||||
// --- General Store Methods ---
|
||||
clearCreateSight = () => {
|
||||
this.needLeaveAgree = false;
|
||||
this.sight = JSON.parse(JSON.stringify(initialSightState)); // Reset to initial
|
||||
};
|
||||
|
||||
@@ -383,6 +388,7 @@ class CreateSightStore {
|
||||
content: Partial<SightLanguageInfo | SightCommonInfo>, // Corrected types
|
||||
language?: Language
|
||||
) => {
|
||||
this.needLeaveAgree = true;
|
||||
if (language) {
|
||||
this.sight[language] = { ...this.sight[language], ...content };
|
||||
} else {
|
||||
@@ -587,10 +593,31 @@ class CreateSightStore {
|
||||
}
|
||||
};
|
||||
|
||||
updateRightArticles = async (articles: any[], language: Language) => {
|
||||
runInAction(() => {
|
||||
this.sight[language].right = articles;
|
||||
});
|
||||
updateRightArticles = async (articles: any[]) => {
|
||||
const articlesIds = articles.map((article) => article.id);
|
||||
|
||||
const sortArticles = (existing: any[]) => {
|
||||
const articleMap = new Map(
|
||||
existing.map((article) => [article.id, article])
|
||||
);
|
||||
return articlesIds
|
||||
.map((id) => articleMap.get(id))
|
||||
.filter(
|
||||
(article): article is (typeof existing)[number] =>
|
||||
article !== undefined
|
||||
);
|
||||
};
|
||||
|
||||
this.sight.ru.right = sortArticles(this.sight.ru.right);
|
||||
this.sight.en.right = sortArticles(this.sight.en.right);
|
||||
this.sight.zh.right = sortArticles(this.sight.zh.right); // теперь zh тоже сортируется одинаково
|
||||
|
||||
this.needLeaveAgree = true;
|
||||
};
|
||||
|
||||
needLeaveAgree = false;
|
||||
setNeedLeaveAgree = (need: boolean) => {
|
||||
this.needLeaveAgree = need;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -170,6 +170,7 @@ class EditSightStore {
|
||||
};
|
||||
|
||||
clearSightInfo = () => {
|
||||
this.needLeaveAgree = false;
|
||||
this.sight = {
|
||||
common: {
|
||||
id: 0,
|
||||
@@ -215,6 +216,7 @@ class EditSightStore {
|
||||
content: Partial<SightLanguageInfo | SightCommonInfo>,
|
||||
common: boolean = false
|
||||
) => {
|
||||
this.needLeaveAgree = true;
|
||||
if (common) {
|
||||
this.sight.common = {
|
||||
...this.sight.common,
|
||||
@@ -262,61 +264,72 @@ class EditSightStore {
|
||||
this.sight.common.left_article != 0 &&
|
||||
this.sight.common.left_article != null
|
||||
) {
|
||||
await languageInstance("ru").patch(
|
||||
`/article/${this.sight.common.left_article}`,
|
||||
{
|
||||
heading: this.sight.ru.left.heading,
|
||||
body: this.sight.ru.left.body,
|
||||
}
|
||||
);
|
||||
await languageInstance("en").patch(
|
||||
`/article/${this.sight.common.left_article}`,
|
||||
{
|
||||
heading: this.sight.en.left.heading,
|
||||
body: this.sight.en.left.body,
|
||||
}
|
||||
);
|
||||
|
||||
await languageInstance("zh").patch(
|
||||
`/article/${this.sight.common.left_article}`,
|
||||
{
|
||||
heading: this.sight.zh.left.heading,
|
||||
body: this.sight.zh.left.body,
|
||||
}
|
||||
);
|
||||
await authInstance.patch(`/article/${this.sight.common.left_article}`, {
|
||||
translation: {
|
||||
ru: {
|
||||
heading: this.sight.ru.left.heading,
|
||||
body: this.sight.ru.left.body,
|
||||
},
|
||||
en: {
|
||||
heading: this.sight.en.left.heading,
|
||||
body: this.sight.en.left.body,
|
||||
},
|
||||
zh: {
|
||||
heading: this.sight.zh.left.heading,
|
||||
body: this.sight.zh.left.body,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await languageInstance("ru").patch(`/sight/${this.sight.common.id}`, {
|
||||
await authInstance.patch(`/sight/${this.sight.common.id}`, {
|
||||
...this.sight.common,
|
||||
name: this.sight.ru.name,
|
||||
address: this.sight.ru.address,
|
||||
left_article: createdLeftArticleId,
|
||||
});
|
||||
await languageInstance("en").patch(`/sight/${this.sight.common.id}`, {
|
||||
...this.sight.common,
|
||||
name: this.sight.en.name,
|
||||
address: this.sight.en.address,
|
||||
left_article: createdLeftArticleId,
|
||||
});
|
||||
await languageInstance("zh").patch(`/sight/${this.sight.common.id}`, {
|
||||
...this.sight.common,
|
||||
name: this.sight.zh.name,
|
||||
address: this.sight.zh.address,
|
||||
left_article: createdLeftArticleId,
|
||||
translation: {
|
||||
ru: {
|
||||
name: this.sight.ru.name,
|
||||
address: this.sight.ru.address,
|
||||
},
|
||||
en: {
|
||||
name: this.sight.en.name,
|
||||
address: this.sight.en.address,
|
||||
},
|
||||
zh: {
|
||||
name: this.sight.zh.name,
|
||||
address: this.sight.zh.address,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const language of ["ru", "en", "zh"] as Language[]) {
|
||||
for (const article of this.sight[language].right) {
|
||||
if (article.id == 0 || article.id == null) {
|
||||
continue;
|
||||
}
|
||||
await languageInstance(language).patch(`/article/${article.id}`, {
|
||||
heading: article.heading,
|
||||
body: article.body,
|
||||
});
|
||||
for (const article of this.sight.ru.right) {
|
||||
if (article.id == 0 || article.id == null) {
|
||||
continue;
|
||||
}
|
||||
await authInstance.patch(`/article/${article.id}`, {
|
||||
translation: {
|
||||
ru: {
|
||||
heading: article.heading,
|
||||
body: article.body,
|
||||
},
|
||||
en: {
|
||||
heading: article.heading,
|
||||
body: article.body,
|
||||
},
|
||||
zh: {
|
||||
heading: article.heading,
|
||||
body: article.body,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const articleIdsInObject = this.sight.ru.right.map((article) => ({
|
||||
id: article.id,
|
||||
}));
|
||||
|
||||
await authInstance.post(`/sight/${this.sight.common.id}/article/order`, {
|
||||
articles: articleIdsInObject,
|
||||
});
|
||||
|
||||
// await languageInstance("ru").patch(
|
||||
// `/sight/${this.sight.common.left_article}/article`,
|
||||
// {
|
||||
@@ -578,19 +591,27 @@ class EditSightStore {
|
||||
};
|
||||
|
||||
createNewRightArticle = async () => {
|
||||
const articleId = await languageInstance("ru").post("/article", {
|
||||
heading: "Введите русский заголовок",
|
||||
body: "Введите русский текст",
|
||||
const articleRuData = {
|
||||
heading: "Новый заголовок (RU)",
|
||||
body: "Новый текст (RU)",
|
||||
};
|
||||
const articleEnData = {
|
||||
heading: "New Heading (EN)",
|
||||
body: "New Text (EN)",
|
||||
};
|
||||
const articleZhData = {
|
||||
heading: "Новый заголовок (ZH)",
|
||||
body: "Новый текст (ZH)",
|
||||
};
|
||||
const articleId = await authInstance.post("/article", {
|
||||
translation: {
|
||||
ru: articleRuData,
|
||||
en: articleEnData,
|
||||
zh: articleZhData,
|
||||
},
|
||||
});
|
||||
const { id } = articleId.data;
|
||||
await languageInstance("en").patch(`/article/${id}`, {
|
||||
heading: "Enter the English heading",
|
||||
body: "Enter the English text",
|
||||
});
|
||||
await languageInstance("zh").patch(`/article/${id}`, {
|
||||
heading: "Введите китайский заголовок",
|
||||
body: "Введите китайский текст",
|
||||
});
|
||||
|
||||
await authInstance.post(`/sight/${this.sight.common.id}/article`, {
|
||||
article_id: id,
|
||||
page_num: this.sight.ru.right.length + 1,
|
||||
@@ -598,20 +619,20 @@ class EditSightStore {
|
||||
|
||||
this.sight.ru.right.push({
|
||||
id: id,
|
||||
heading: "Введите русский заголовок",
|
||||
body: "Введите русский текст",
|
||||
heading: articleRuData.heading,
|
||||
body: articleRuData.body,
|
||||
media: [],
|
||||
});
|
||||
this.sight.en.right.push({
|
||||
id: id,
|
||||
heading: "Enter the English heading",
|
||||
body: "Enter the English text",
|
||||
heading: articleEnData.heading,
|
||||
body: articleEnData.body,
|
||||
media: [],
|
||||
});
|
||||
this.sight.zh.right.push({
|
||||
id: id,
|
||||
heading: "Введите китайский заголовок",
|
||||
body: "Введите китайский текст",
|
||||
heading: articleZhData.heading,
|
||||
body: articleZhData.body,
|
||||
media: [],
|
||||
});
|
||||
};
|
||||
@@ -671,14 +692,31 @@ class EditSightStore {
|
||||
this.sight[language].right[index].body = body;
|
||||
};
|
||||
|
||||
updateRightArticles = async (articles: any[], language: Language) => {
|
||||
this.sight[language].right = articles;
|
||||
const articleIdsInObject = articles.map((article) => ({
|
||||
id: article.id,
|
||||
}));
|
||||
await authInstance.post(`/sight/${this.sight.common.id}/article/order`, {
|
||||
articles: articleIdsInObject,
|
||||
});
|
||||
updateRightArticles = async (articles: any[]) => {
|
||||
const articlesIds = articles.map((article) => article.id);
|
||||
|
||||
const sortArticles = (existing: any[]) => {
|
||||
const articleMap = new Map(
|
||||
existing.map((article) => [article.id, article])
|
||||
);
|
||||
return articlesIds
|
||||
.map((id) => articleMap.get(id))
|
||||
.filter(
|
||||
(article): article is (typeof existing)[number] =>
|
||||
article !== undefined
|
||||
);
|
||||
};
|
||||
|
||||
this.sight.ru.right = sortArticles(this.sight.ru.right);
|
||||
this.sight.en.right = sortArticles(this.sight.en.right);
|
||||
this.sight.zh.right = sortArticles(this.sight.zh.right); // теперь zh тоже сортируется одинаково
|
||||
|
||||
this.needLeaveAgree = true;
|
||||
};
|
||||
|
||||
needLeaveAgree = false;
|
||||
setNeedLeaveAgree = (need: boolean) => {
|
||||
this.needLeaveAgree = need;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user