fix: Language cache sight

This commit is contained in:
2025-05-31 21:17:27 +03:00
parent 2e6917406e
commit 0d9bbb140f
28 changed files with 2760 additions and 1013 deletions

View File

@ -4,6 +4,12 @@ import {
Box,
Autocomplete,
Typography,
Paper,
Tooltip,
Dialog,
DialogTitle,
MenuItem,
Menu as MuiMenu,
} from "@mui/material";
import {
BackButton,
@ -14,24 +20,70 @@ import {
Language,
cityStore,
CoordinatesInput,
editSightStore,
SelectMediaDialog,
PreviewMediaDialog,
} from "@shared";
import { LanguageSwitcher } from "@widgets";
import { Info, ImagePlus } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useState } from "react";
import { useRef, useState } from "react";
// Мокап для всплывающей подсказки
export const InformationTab = observer(
({ value, index }: { value: number; index: number }) => {
const { cities } = cityStore;
const [isMediaModalOpen, setIsMediaModalOpen] = useState(false);
const [mediaId, setMediaId] = useState<string>("");
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
const { createSight, updateCreateSight, createSightAction } = sightsStore;
const [city, setCity] = useState<number>(0);
const { sightInfo } = editSightStore;
const [city, setCity] = useState<number>(sightInfo.city_id ?? 0);
const [coordinates, setCoordinates] = useState({
latitude: 0,
longitude: 0,
latitude: sightInfo.latitude ?? 0,
longitude: sightInfo.longitude ?? 0,
});
const { language } = languageStore;
const token = localStorage.getItem("token");
// Menu state for each media button
const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
const [activeMenuType, setActiveMenuType] = useState<
"thumbnail" | "watermark_lu" | "watermark_rd" | null
>(null);
const [isAddMediaOpen, setIsAddMediaOpen] = useState(false);
const handleMenuOpen = (
event: React.MouseEvent<HTMLElement>,
type: "thumbnail" | "watermark_lu" | "watermark_rd"
) => {
setMenuAnchorEl(event.currentTarget);
setActiveMenuType(type);
};
const handleMenuClose = () => {
setMenuAnchorEl(null);
setActiveMenuType(null);
};
const handleCreateNew = () => {
handleMenuClose();
};
const handleAddMedia = () => {
setIsAddMediaOpen(true);
handleMenuClose();
};
const handleMediaSelect = (selectedMediaId: string) => {
if (!activeMenuType) return;
// Close the dialog
setIsAddMediaOpen(false);
setActiveMenuType(null);
};
const handleChange = (
language: Language,
@ -42,325 +94,326 @@ export const InformationTab = observer(
const handleSave = async () => {
try {
await createSightAction(createSight[language], city, coordinates);
await createSightAction(city, coordinates);
} catch (error) {
console.error(error);
}
};
return (
<TabPanel value={value} index={index}>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 3,
position: "relative",
paddingBottom: "70px" /* Space for save button */,
}}
>
<BackButton />
<>
<TabPanel value={value} index={index}>
<Box
sx={{
display: "flex",
gap: 4, // Added gap between the two main columns
width: "100%",
flexDirection: "column",
gap: 3,
position: "relative",
paddingBottom: "70px" /* Space for save button */,
}}
>
{/* Left column with main fields */}
<BackButton />
<Box
sx={{
flexGrow: 1,
display: "flex",
width: "80%",
gap: 4, // Added gap between the two main columns
width: "100%",
flexDirection: "column",
gap: 2.5,
}}
>
<TextField
label={`Название (${language.toUpperCase()})`}
value={createSight[language]?.name ?? ""}
onChange={(e) => {
handleChange(language as Language, {
name: e.target.value,
});
{/* Left column with main fields */}
<Box
sx={{
flexGrow: 1,
display: "flex",
width: "80%",
flexDirection: "column",
gap: 2.5,
}}
fullWidth
variant="outlined"
/>
<TextField
label={`Описание (${language.toUpperCase()})`}
value={createSight?.[language]?.description ?? ""}
onChange={(e) => {
handleChange(language as Language, {
description: e.target.value,
});
}}
fullWidth
variant="outlined"
multiline
rows={4}
/>
<TextField
label="Адрес"
value={createSight?.[language]?.address ?? ""}
onChange={(e) => {
handleChange(language as Language, {
address: e.target.value,
});
}}
fullWidth
variant="outlined"
/>
<Autocomplete
options={cities}
getOptionLabel={(option) => option.name}
onChange={(_, value) => {
setCity(value?.id ?? 0);
}}
renderInput={(params) => (
<TextField {...params} label="Город" />
)}
/>
>
<TextField
label={`Название (${language.toUpperCase()})`}
value={sightInfo[language]?.info?.name ?? ""}
onChange={(e) => {
handleChange(language as Language, {
name: e.target.value,
});
}}
fullWidth
variant="outlined"
/>
<CoordinatesInput setValue={setCoordinates} />
</Box>
<TextField
label="Адрес"
value={sightInfo[language]?.info?.address ?? ""}
onChange={(e) => {
handleChange(language as Language, {
address: e.target.value,
});
}}
fullWidth
variant="outlined"
/>
{/* Правая колонка для логотипа и водяных знаков
<Box
sx={{
display: "flex",
<Autocomplete
options={cities}
value={cities.find((city) => city.id === sightInfo.city_id)}
getOptionLabel={(option) => option.name}
onChange={(_, value) => {
setCity(value?.id ?? 0);
}}
renderInput={(params) => (
<TextField {...params} label="Город" />
)}
/>
gap: 4,
}}
>
<CoordinatesInput
initialValue={coordinates}
setValue={setCoordinates}
/>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-around",
width: "80%",
gap: 2,
flexDirection: { xs: "column", sm: "row" }, // Stack on extra small, side-by-side on small and up
gap: 4,
}}
>
<Paper
elevation={2}
<Box
sx={{
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
justifyContent: "space-around",
width: "80%",
gap: 2,
flexDirection: { xs: "column", sm: "row" }, // Stack on extra small, side-by-side on small and up
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
>
Логотип
</Typography>
<Tooltip title={watermarkTooltipText}>
<Info
size={16}
color="gray"
style={{ cursor: "pointer" }}
/>
</Tooltip>
</Box>
<Box
<Paper
elevation={2}
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: mockSightData.watermark_lu
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: mockSightData.watermark_lu
? "grey.300"
: "grey.200",
},
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
}}
onClick={() =>
mockSightData.watermark_lu &&
handleSelectMedia("watermark_lu")
}
>
{mockSightData.watermark_lu ? (
<img
src={mockSightData.watermark_lu}
alt="Знак л.в"
style={{ maxWidth: "100%", maxHeight: "100%" }}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={() => handleSelectMedia("watermark_lu")}
>
Выбрать
</Button>
</Paper>
<Paper
elevation={2}
sx={{
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
>
Логотип
</Typography>
</Box>
<Box
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: editSightStore.sightInfo?.thumbnail
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: editSightStore.sightInfo?.thumbnail
? "red.300"
: "grey.200",
},
}}
onClick={() => {
setIsMediaModalOpen(true);
}}
>
Водяной знак (л.в)
</Typography>
<Tooltip title={watermarkTooltipText}>
<Info
size={16}
color="gray"
style={{ cursor: "pointer" }}
/>
</Tooltip>
</Box>
<Box
{editSightStore.sightInfo?.thumbnail ? (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
editSightStore.sightInfo?.thumbnail
}/download?token=${token}`}
alt="Логотип"
style={{ maxWidth: "100%", maxHeight: "100%" }}
onClick={() => {
setIsPreviewMediaOpen(true);
setMediaId(editSightStore.sightInfo?.thumbnail);
}}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={(e) => handleMenuOpen(e, "thumbnail")}
>
Выбрать
</Button>
</Paper>
<Paper
elevation={2}
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: mockSightData.watermark_lu
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: mockSightData.watermark_lu
? "grey.300"
: "grey.200",
},
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
}}
onClick={() =>
mockSightData.watermark_lu &&
handleSelectMedia("watermark_lu")
}
>
{mockSightData.watermark_lu ? (
<img
src={mockSightData.watermark_lu}
alt="Знак л.в"
style={{ maxWidth: "100%", maxHeight: "100%" }}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={() => handleSelectMedia("watermark_lu")}
>
Выбрать
</Button>
</Paper>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
>
Водяной знак (л.в)
</Typography>
<Tooltip title={"asf"}>
<Info
size={16}
color="gray"
style={{ cursor: "pointer" }}
/>
</Tooltip>
</Box>
<Box
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: editSightStore.sightInfo?.watermark_lu
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: editSightStore.sightInfo
?.watermark_lu
? "grey.300"
: "grey.200",
},
}}
onClick={() => {
setIsPreviewMediaOpen(true);
setMediaId(editSightStore.sightInfo?.watermark_lu);
}}
>
{editSightStore.sightInfo?.watermark_lu ? (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
editSightStore.sightInfo?.watermark_lu
}/download?token=${token}`}
alt="Знак л.в"
style={{ maxWidth: "100%", maxHeight: "100%" }}
onClick={() => {
setIsMediaModalOpen(true);
setMediaId(editSightStore.sightInfo?.watermark_lu);
}}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={(e) => handleMenuOpen(e, "watermark_lu")}
>
Выбрать
</Button>
</Paper>
<Paper
elevation={2}
sx={{
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
>
Водяной знак (п.в)
</Typography>
<Tooltip title={watermarkTooltipText}>
<Info
size={16}
color="gray"
style={{ cursor: "pointer" }}
/>
</Tooltip>
</Box>
<Box
<Paper
elevation={2}
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
padding: 2,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: mockSightData.watermark_rd
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: mockSightData.watermark_rd
? "grey.300"
: "grey.200",
},
gap: 1,
flex: 1,
minWidth: 150, // Ensure a minimum width
}}
onClick={() =>
mockSightData.watermark_rd &&
handleSelectMedia("watermark_rd")
}
>
{mockSightData.watermark_rd ? (
<img
src={mockSightData.watermark_rd}
alt="Знак п.в"
style={{ maxWidth: "100%", maxHeight: "100%" }}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={() => handleSelectMedia("watermark_rd")}
>
Выбрать
</Button>
</Paper>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Typography
variant="subtitle2"
gutterBottom
sx={{ mb: 0, mr: 0.5 }}
>
Водяной знак (п.в)
</Typography>
<Tooltip title={"asfaf"}>
<Info
size={16}
color="gray"
style={{ cursor: "pointer" }}
/>
</Tooltip>
</Box>
<Box
sx={{
width: 80,
height: 80,
backgroundColor: "grey.200",
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
mb: 1,
cursor: editSightStore.sightInfo?.watermark_rd
? "pointer"
: "default", // Only clickable if there's an image
"&:hover": {
backgroundColor: editSightStore.sightInfo
?.watermark_rd
? "grey.300"
: "grey.200",
},
}}
onClick={() => editSightStore.sightInfo?.watermark_rd}
>
{editSightStore.sightInfo?.watermark_rd ? (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
editSightStore.sightInfo?.watermark_rd
}/download?token=${token}`}
alt="Знак п.в"
style={{ maxWidth: "100%", maxHeight: "100%" }}
onClick={() => {
setIsPreviewMediaOpen(true);
setMediaId(editSightStore.sightInfo?.watermark_rd);
}}
/>
) : (
<ImagePlus size={24} color="grey" />
)}
</Box>
<Button
variant="outlined"
size="small"
onClick={(e) => handleMenuOpen(e, "watermark_rd")}
>
Выбрать
</Button>
</Paper>
</Box>
</Box>
</Box>
</Box> */}
{/* LanguageSwitcher positioned at the top right */}
@ -384,8 +437,41 @@ export const InformationTab = observer(
</Button>
</Box>
</Box>
</Box>
</TabPanel>
</TabPanel>
{/* Media Menu */}
<MuiMenu
anchorEl={menuAnchorEl}
open={Boolean(menuAnchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
transformOrigin={{
vertical: "bottom",
horizontal: "right",
}}
>
<MenuItem onClick={handleCreateNew}>Создать новую</MenuItem>
<MenuItem onClick={handleAddMedia}>Выбрать существующую</MenuItem>
</MuiMenu>
<SelectMediaDialog
open={isAddMediaOpen}
onClose={() => {
setIsAddMediaOpen(false);
setActiveMenuType(null);
}}
onSelectArticle={handleMediaSelect}
/>
<PreviewMediaDialog
open={isPreviewMediaOpen}
onClose={() => setIsPreviewMediaOpen(false)}
mediaId={mediaId}
/>
</>
);
}
);