WhiteNightsAdminPanel/src/widgets/SightTabs/LeftWidgetTab/index.tsx
2025-06-01 23:18:21 +03:00

346 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @widgets/LeftWidgetTab.tsx
import { Box, Button, TextField, Paper, Typography } from "@mui/material";
import {
BackButton,
TabPanel,
languageStore,
SelectMediaDialog,
editSightStore,
SelectArticleModal,
UploadMediaDialog,
} from "@shared";
import {
LanguageSwitcher,
ReactMarkdownComponent,
ReactMarkdownEditor,
MediaArea,
MediaViewer,
} from "@widgets";
import { Trash2, ImagePlus } from "lucide-react";
import { useState, useCallback } from "react";
import { observer } from "mobx-react-lite";
import { toast } from "react-toastify";
export const LeftWidgetTab = observer(
({ value, index }: { value: number; index: number }) => {
const {
sight,
updateSightInfo,
unlinkLeftArticle,
updateSight,
deleteLeftArticle,
createLeftArticle,
deleteMedia,
uploadMediaOpen,
setUploadMediaOpen,
setFileToUpload,
createLinkWithArticle,
} = editSightStore;
const { language } = languageStore;
const data = sight[language];
const [isSelectMediaDialogOpen, setIsSelectMediaDialogOpen] =
useState(false);
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
useState(false);
const handleMediaSelected = useCallback(
async (media: {
id: string;
filename: string;
media_name?: string;
media_type: number;
}) => {
await createLinkWithArticle(media);
setIsSelectMediaDialogOpen(false);
},
[createLinkWithArticle]
);
const handleCloseMediaDialog = useCallback(() => {
setIsSelectMediaDialogOpen(false);
}, []);
const handleCloseArticleDialog = useCallback(() => {
setIsSelectArticleDialogOpen(false);
}, []);
const handleSelectArticle = useCallback(
(
articleId: number,
heading: string,
body: string,
media: { id: string; media_type: number; filename: string }[]
) => {
setIsSelectArticleDialogOpen(false);
updateSightInfo(languageStore.language, {
left: {
heading,
body,
media,
},
});
updateSightInfo(
languageStore.language,
{
left_article: articleId,
},
true
);
},
[]
);
return (
<>
<TabPanel value={value} index={index}>
<LanguageSwitcher />
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 3,
paddingBottom: "70px",
position: "relative",
}}
>
<BackButton />
<Paper
elevation={2}
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
paddingX: 2.5,
paddingY: 1.5,
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
}}
>
<Typography variant="h6">Левая статья</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
{sight.common.left_article ? (
<>
<Button
variant="contained"
color="primary"
size="small"
style={{ transition: "0" }}
onClick={() => {
unlinkLeftArticle();
toast.success("Статья откреплена");
}}
>
Открепить
</Button>
<Button
variant="outlined"
color="error"
style={{ transition: "0" }}
startIcon={<Trash2 size={18} />}
size="small"
onClick={() => {
deleteLeftArticle(sight.common.left_article);
toast.success("Статья откреплена");
}}
>
Удалить
</Button>
</>
) : (
<>
<Button
variant="contained"
color="primary"
size="small"
onClick={() => setIsSelectArticleDialogOpen(true)}
>
Выбрать статью
</Button>
<Button
variant="contained"
color="primary"
size="small"
style={{ transition: "0" }}
onClick={() => {
createLeftArticle();
toast.success("Статья создана");
}}
>
Создать статью
</Button>
</>
)}
</Box>
</Paper>
{sight.common.left_article > 0 && (
<Box sx={{ display: "flex", gap: 3, flexGrow: 1 }}>
<Box
sx={{
flex: 2,
display: "flex",
flexDirection: "column",
gap: 2,
}}
>
<TextField
label="Название информации"
value={data?.left?.heading}
onChange={(e) =>
updateSightInfo(languageStore.language, {
left: {
heading: e.target.value,
body: sight[languageStore.language].left.body,
media: data.left.media,
},
})
}
variant="outlined"
fullWidth
/>
<ReactMarkdownEditor
value={data?.left?.body}
onChange={(value) =>
updateSightInfo(languageStore.language, {
left: {
heading: sight[languageStore.language].left.heading,
body: value,
media: data.left.media,
},
})
}
/>
<MediaArea
articleId={sight.common.left_article}
mediaIds={data.left.media}
deleteMedia={deleteMedia}
setSelectMediaDialogOpen={setIsSelectMediaDialogOpen}
onFilesDrop={(files) => {
setFileToUpload(files[0]);
setUploadMediaOpen(true);
}}
/>
</Box>
<Box
sx={{
flex: 1,
display: "flex",
flexDirection: "column",
gap: 1.5,
}}
>
<Paper
elevation={3}
sx={{
width: "100%",
minWidth: 320,
maxWidth: 400,
height: "auto",
minHeight: 500,
backgroundColor: "#877361",
overflowY: "auto",
padding: 0,
display: "flex",
flexDirection: "column",
}}
>
<Box
sx={{
width: "100%",
height: 200,
backgroundColor: "grey.300",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{data.left.media.length > 0 ? (
<MediaViewer
media={{
id: data.left.media[0].id,
media_type: data.left.media[0].media_type,
filename: data.left.media[0].filename,
}}
/>
) : (
<ImagePlus size={48} color="grey" />
)}
</Box>
<Box
sx={{
backgroundColor: "#877361",
color: "white",
padding: 1.5,
}}
>
<Typography
variant="h5"
component="h2"
sx={{ wordBreak: "break-word" }}
>
{data?.left?.heading || "Название информации"}
</Typography>
</Box>
{data?.left?.body && (
<Box
sx={{
padding: 2,
flexGrow: 1,
}}
>
<ReactMarkdownComponent value={data?.left?.body} />
</Box>
)}
</Paper>
</Box>
</Box>
)}
<Box sx={{ position: "absolute", bottom: 0, right: 0, padding: 2 }}>
<Button
variant="contained"
color="success"
onClick={async () => {
await updateSight();
toast.success("Достопримечательность сохранена");
}}
>
Сохранить
</Button>
</Box>
</Box>
</TabPanel>
<UploadMediaDialog
open={uploadMediaOpen}
onClose={() => setUploadMediaOpen(false)}
afterUpload={async (media) => {
setUploadMediaOpen(false);
setFileToUpload(null);
await createLinkWithArticle(media);
}}
/>
<SelectMediaDialog
open={isSelectMediaDialogOpen}
onClose={handleCloseMediaDialog}
onSelectMedia={handleMediaSelected}
/>
<SelectArticleModal
open={isSelectArticleDialogOpen}
onClose={handleCloseArticleDialog}
onSelectArticle={handleSelectArticle}
/>
</>
);
}
);