feat: Improving page loading
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box } from "@mui/material";
|
||||
import { PreviewLeftWidget } from "./PreviewLeftWidget";
|
||||
import { PreviewRightWidget } from "./PreviewRightWidget";
|
||||
import { articlesStore, languageStore } from "@shared";
|
||||
import { articlesStore, languageStore, LoadingSpinner } from "@shared";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
|
||||
export const ArticlePreviewPage = () => {
|
||||
@@ -11,18 +11,41 @@ export const ArticlePreviewPage = () => {
|
||||
const { id } = useParams();
|
||||
const { getArticle, getArticleMedia, getArticlePreview } = articlesStore;
|
||||
const { language } = languageStore;
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
if (id) {
|
||||
await getArticle(Number(id), language);
|
||||
await getArticleMedia(Number(id));
|
||||
await getArticlePreview(Number(id));
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
await getArticle(Number(id), language);
|
||||
await getArticleMedia(Number(id));
|
||||
await getArticlePreview(Number(id));
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, [id, language]);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных статьи..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex items-center gap-4 mb-10">
|
||||
|
||||
@@ -6,13 +6,20 @@ import {
|
||||
MenuItem,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft, Save } from "lucide-react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import { carrierStore, cityStore, mediaStore, languageStore } from "@shared";
|
||||
import {
|
||||
carrierStore,
|
||||
cityStore,
|
||||
mediaStore,
|
||||
languageStore,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { useState, useEffect } from "react";
|
||||
import { ImageUploadCard, LanguageSwitcher, DeleteModal } from "@widgets";
|
||||
import {
|
||||
@@ -28,6 +35,7 @@ export const CarrierEditPage = observer(() => {
|
||||
const { language } = languageStore;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const [isSelectMediaOpen, setIsSelectMediaOpen] = useState(false);
|
||||
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
||||
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
||||
@@ -39,39 +47,48 @@ export const CarrierEditPage = observer(() => {
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await cityStore.getCities("ru");
|
||||
await cityStore.getCities("en");
|
||||
await cityStore.getCities("zh");
|
||||
const carrierData = await getCarrier(Number(id));
|
||||
|
||||
if (carrierData) {
|
||||
setEditCarrierData(
|
||||
carrierData.ru?.full_name || "",
|
||||
carrierData.ru?.short_name || "",
|
||||
carrierData.ru?.city_id || 0,
|
||||
carrierData.ru?.slogan || "",
|
||||
carrierData.ru?.logo || "",
|
||||
"ru"
|
||||
);
|
||||
setEditCarrierData(
|
||||
carrierData.en?.full_name || "",
|
||||
carrierData.en?.short_name || "",
|
||||
carrierData.en?.city_id || 0,
|
||||
carrierData.en?.slogan || "",
|
||||
carrierData.en?.logo || "",
|
||||
"en"
|
||||
);
|
||||
setEditCarrierData(
|
||||
carrierData.zh?.full_name || "",
|
||||
carrierData.zh?.short_name || "",
|
||||
carrierData.zh?.city_id || 0,
|
||||
carrierData.zh?.slogan || "",
|
||||
carrierData.zh?.logo || "",
|
||||
"zh"
|
||||
);
|
||||
if (!id) {
|
||||
setIsLoadingData(false);
|
||||
return;
|
||||
}
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
await cityStore.getCities("ru");
|
||||
await cityStore.getCities("en");
|
||||
await cityStore.getCities("zh");
|
||||
const carrierData = await getCarrier(Number(id));
|
||||
|
||||
mediaStore.getMedia();
|
||||
if (carrierData) {
|
||||
setEditCarrierData(
|
||||
carrierData.ru?.full_name || "",
|
||||
carrierData.ru?.short_name || "",
|
||||
carrierData.ru?.city_id || 0,
|
||||
carrierData.ru?.slogan || "",
|
||||
carrierData.ru?.logo || "",
|
||||
"ru"
|
||||
);
|
||||
setEditCarrierData(
|
||||
carrierData.en?.full_name || "",
|
||||
carrierData.en?.short_name || "",
|
||||
carrierData.en?.city_id || 0,
|
||||
carrierData.en?.slogan || "",
|
||||
carrierData.en?.logo || "",
|
||||
"en"
|
||||
);
|
||||
setEditCarrierData(
|
||||
carrierData.zh?.full_name || "",
|
||||
carrierData.zh?.short_name || "",
|
||||
carrierData.zh?.city_id || 0,
|
||||
carrierData.zh?.slogan || "",
|
||||
carrierData.zh?.logo || "",
|
||||
"zh"
|
||||
);
|
||||
}
|
||||
|
||||
await mediaStore.getMedia();
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
})();
|
||||
|
||||
languageStore.setLanguage("ru");
|
||||
@@ -110,6 +127,21 @@ export const CarrierEditPage = observer(() => {
|
||||
? mediaStore.media.find((m) => m.id === editCarrierData.logo)
|
||||
: null;
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных перевозчика..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<LanguageSwitcher />
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
MenuItem,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft, Save } from "lucide-react";
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
languageStore,
|
||||
mediaStore,
|
||||
CashedCities,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LanguageSwitcher, ImageUploadCard } from "@widgets";
|
||||
@@ -30,6 +32,7 @@ import {
|
||||
export const CityEditPage = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const [isSelectMediaOpen, setIsSelectMediaOpen] = useState(false);
|
||||
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
||||
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
||||
@@ -62,19 +65,26 @@ export const CityEditPage = observer(() => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (id) {
|
||||
await getCountries("ru");
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
await getCountries("ru");
|
||||
|
||||
const ruData = await getCity(id as string, "ru");
|
||||
const enData = await getCity(id as string, "en");
|
||||
const zhData = await getCity(id as string, "zh");
|
||||
const ruData = await getCity(id as string, "ru");
|
||||
const enData = await getCity(id as string, "en");
|
||||
const zhData = await getCity(id as string, "zh");
|
||||
|
||||
setEditCityData(ruData.name, ruData.country_code, ruData.arms, "ru");
|
||||
setEditCityData(enData.name, enData.country_code, enData.arms, "en");
|
||||
setEditCityData(zhData.name, zhData.country_code, zhData.arms, "zh");
|
||||
setEditCityData(ruData.name, ruData.country_code, ruData.arms, "ru");
|
||||
setEditCityData(enData.name, enData.country_code, enData.arms, "en");
|
||||
setEditCityData(zhData.name, zhData.country_code, zhData.arms, "zh");
|
||||
|
||||
await getOneMedia(ruData.arms as string);
|
||||
await getOneMedia(ruData.arms as string);
|
||||
|
||||
await getMedia();
|
||||
await getMedia();
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
})();
|
||||
}, [id]);
|
||||
@@ -97,6 +107,21 @@ export const CityEditPage = observer(() => {
|
||||
? mediaStore.media.find((m) => m.id === editCityData.arms)
|
||||
: null;
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных города..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<LanguageSwitcher />
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Button, Paper, TextField } from "@mui/material";
|
||||
import { Button, Paper, TextField, Box } from "@mui/material";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft, Save } from "lucide-react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import { countryStore, languageStore } from "@shared";
|
||||
import { countryStore, languageStore, LoadingSpinner } from "@shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LanguageSwitcher } from "@widgets";
|
||||
|
||||
export const CountryEditPage = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const { language } = languageStore;
|
||||
const { id } = useParams();
|
||||
const { editCountryData, editCountry, getCountry, setEditCountryData } =
|
||||
@@ -35,17 +36,39 @@ export const CountryEditPage = observer(() => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (id) {
|
||||
const ruData = await getCountry(id as string, "ru");
|
||||
const enData = await getCountry(id as string, "en");
|
||||
const zhData = await getCountry(id as string, "zh");
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
const ruData = await getCountry(id as string, "ru");
|
||||
const enData = await getCountry(id as string, "en");
|
||||
const zhData = await getCountry(id as string, "zh");
|
||||
|
||||
setEditCountryData(ruData.name, "ru");
|
||||
setEditCountryData(enData.name, "en");
|
||||
setEditCountryData(zhData.name, "zh");
|
||||
setEditCountryData(ruData.name, "ru");
|
||||
setEditCountryData(enData.name, "en");
|
||||
setEditCountryData(zhData.name, "zh");
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
})();
|
||||
}, [id]);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных страны..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<LanguageSwitcher />
|
||||
|
||||
@@ -3,7 +3,12 @@ import { InformationTab, LeaveAgree, RightWidgetTab } from "@widgets";
|
||||
import { LeftWidgetTab } from "@widgets";
|
||||
import { useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { articlesStore, cityStore, editSightStore } from "@shared";
|
||||
import {
|
||||
articlesStore,
|
||||
cityStore,
|
||||
editSightStore,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { useBlocker, useParams } from "react-router-dom";
|
||||
|
||||
function a11yProps(index: number) {
|
||||
@@ -15,6 +20,7 @@ function a11yProps(index: number) {
|
||||
|
||||
export const EditSightPage = observer(() => {
|
||||
const [value, setValue] = useState(0);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const { sight, getSightInfo, needLeaveAgree } = editSightStore;
|
||||
const { getArticles } = articlesStore;
|
||||
|
||||
@@ -33,13 +39,20 @@ export const EditSightPage = observer(() => {
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
if (id) {
|
||||
await getCities("ru");
|
||||
await getSightInfo(+id, "ru");
|
||||
await getSightInfo(+id, "en");
|
||||
await getSightInfo(+id, "zh");
|
||||
await getArticles("ru");
|
||||
await getArticles("en");
|
||||
await getArticles("zh");
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
await getCities("ru");
|
||||
await getSightInfo(+id, "ru");
|
||||
await getSightInfo(+id, "en");
|
||||
await getSightInfo(+id, "zh");
|
||||
await getArticles("ru");
|
||||
await getArticles("en");
|
||||
await getArticles("zh");
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
@@ -79,12 +92,25 @@ export const EditSightPage = observer(() => {
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
{sight.common.id !== 0 && (
|
||||
<div className="flex-1">
|
||||
<InformationTab value={value} index={0} />
|
||||
<LeftWidgetTab value={value} index={1} />
|
||||
<RightWidgetTab value={value} index={2} />
|
||||
</div>
|
||||
{isLoadingData ? (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных достопримечательности..." />
|
||||
</Box>
|
||||
) : (
|
||||
sight.common.id !== 0 && (
|
||||
<div className="flex-1">
|
||||
<InformationTab value={value} index={0} />
|
||||
<LeftWidgetTab value={value} index={1} />
|
||||
<RightWidgetTab value={value} index={2} />
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{blocker.state === "blocked" ? <LeaveAgree blocker={blocker} /> : null}
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
mediaStore,
|
||||
MEDIA_TYPE_LABELS,
|
||||
languageStore,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { MediaViewer } from "@widgets";
|
||||
|
||||
@@ -138,8 +139,15 @@ export const MediaEditPage = observer(() => {
|
||||
|
||||
if (!media && id) {
|
||||
return (
|
||||
<Box className="flex justify-center items-center h-screen">
|
||||
<CircularProgress />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных медиа..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
ArticleSelectOrCreateDialog,
|
||||
SelectMediaDialog,
|
||||
UploadMediaDialog,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { toast } from "react-toastify";
|
||||
import { stationsStore } from "@shared";
|
||||
@@ -37,6 +38,7 @@ export const RouteEditPage = observer(() => {
|
||||
const { id } = useParams();
|
||||
const { editRouteData, copyRouteAction } = routeStore;
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
|
||||
useState(false);
|
||||
const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false);
|
||||
@@ -48,18 +50,27 @@ export const RouteEditPage = observer(() => {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await routeStore.getRoute(Number(id));
|
||||
routeStore.setEditRouteData(response);
|
||||
languageStore.setLanguage("ru");
|
||||
if (!id) {
|
||||
setIsLoadingData(false);
|
||||
return;
|
||||
}
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
const response = await routeStore.getRoute(Number(id));
|
||||
routeStore.setEditRouteData(response);
|
||||
languageStore.setLanguage("ru");
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
carrierStore.getCarriers(language);
|
||||
stationsStore.getStations();
|
||||
articlesStore.getArticleList();
|
||||
await carrierStore.getCarriers(language);
|
||||
await stationsStore.getStations();
|
||||
await articlesStore.getArticleList();
|
||||
};
|
||||
fetchData();
|
||||
}, [id, language]);
|
||||
@@ -233,6 +244,21 @@ export const RouteEditPage = observer(() => {
|
||||
(article) => article.id === editRouteData.governor_appeal
|
||||
);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных маршрута..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<div className="flex items-center gap-4">
|
||||
|
||||
@@ -6,13 +6,19 @@ import {
|
||||
MenuItem,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft, Save } from "lucide-react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import { stationsStore, languageStore, cityStore } from "@shared";
|
||||
import {
|
||||
stationsStore,
|
||||
languageStore,
|
||||
cityStore,
|
||||
LoadingSpinner,
|
||||
} from "@shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { LanguageSwitcher } from "@widgets";
|
||||
import { LinkedSights } from "../LinkedSights";
|
||||
@@ -21,6 +27,7 @@ import { SaveWithoutCityAgree } from "@widgets";
|
||||
export const StationEditPage = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
const { language } = languageStore;
|
||||
const { id } = useParams();
|
||||
const {
|
||||
@@ -90,18 +97,41 @@ export const StationEditPage = observer(() => {
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAndSetStationData = async () => {
|
||||
if (!id) return;
|
||||
if (!id) {
|
||||
setIsLoadingData(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const stationId = Number(id);
|
||||
await getEditStation(stationId);
|
||||
await getCities("ru");
|
||||
await getCities("en");
|
||||
await getCities("zh");
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
const stationId = Number(id);
|
||||
await getEditStation(stationId);
|
||||
await getCities("ru");
|
||||
await getCities("en");
|
||||
await getCities("zh");
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchAndSetStationData();
|
||||
}, [id]);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных станции..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<LanguageSwitcher />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Paper } from "@mui/material";
|
||||
import { languageStore, stationsStore } from "@shared";
|
||||
import { Paper, Box } from "@mui/material";
|
||||
import { languageStore, stationsStore, LoadingSpinner } from "@shared";
|
||||
import { LanguageSwitcher } from "@widgets";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { LinkedSights } from "../LinkedSights";
|
||||
|
||||
@@ -12,15 +12,38 @@ export const StationPreviewPage = observer(() => {
|
||||
const { stationPreview, getStationPreview } = stationsStore;
|
||||
const navigate = useNavigate();
|
||||
const { language } = languageStore;
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (id) {
|
||||
await getStationPreview(Number(id));
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
await getStationPreview(Number(id));
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
})();
|
||||
}, [id, language]);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных станции..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full p-3 py-5 flex flex-col gap-10">
|
||||
<LanguageSwitcher />
|
||||
|
||||
@@ -4,18 +4,20 @@ import {
|
||||
Checkbox,
|
||||
Paper,
|
||||
TextField,
|
||||
Box,
|
||||
} from "@mui/material";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ArrowLeft, Save } from "lucide-react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import { userStore, languageStore } from "@shared";
|
||||
import { userStore, languageStore, LoadingSpinner } from "@shared";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const UserEditPage = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||
|
||||
const { id } = useParams();
|
||||
const { editUserData, editUser, getUser, setEditUserData } = userStore;
|
||||
@@ -41,18 +43,40 @@ export const UserEditPage = observer(() => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (id) {
|
||||
const data = await getUser(Number(id));
|
||||
setIsLoadingData(true);
|
||||
try {
|
||||
const data = await getUser(Number(id));
|
||||
|
||||
setEditUserData(
|
||||
data?.name || "",
|
||||
data?.email || "",
|
||||
data?.password || "",
|
||||
data?.is_admin || false
|
||||
);
|
||||
setEditUserData(
|
||||
data?.name || "",
|
||||
data?.email || "",
|
||||
data?.password || "",
|
||||
data?.is_admin || false
|
||||
);
|
||||
} finally {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
} else {
|
||||
setIsLoadingData(false);
|
||||
}
|
||||
})();
|
||||
}, [id]);
|
||||
|
||||
if (isLoadingData) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
minHeight: "60vh",
|
||||
}}
|
||||
>
|
||||
<LoadingSpinner message="Загрузка данных пользователя..." />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||||
<div className="flex items-center gap-4">
|
||||
|
||||
@@ -86,28 +86,35 @@ class EditSightStore {
|
||||
}
|
||||
|
||||
hasLoadedCommon = false;
|
||||
isLoading = false;
|
||||
|
||||
getSightInfo = async (id: number, language: Language) => {
|
||||
const response = await languageInstance(language).get(`/sight/${id}`);
|
||||
const data = response.data;
|
||||
this.isLoading = true;
|
||||
try {
|
||||
const response = await languageInstance(language).get(`/sight/${id}`);
|
||||
const data = response.data;
|
||||
|
||||
if (data.left_article != 0 && data.left_article != null) {
|
||||
await this.getLeftArticle(data.left_article);
|
||||
}
|
||||
if (data.left_article != 0 && data.left_article != null) {
|
||||
await this.getLeftArticle(data.left_article);
|
||||
}
|
||||
|
||||
runInAction(() => {
|
||||
this.sight[language] = {
|
||||
...this.sight[language],
|
||||
...data,
|
||||
};
|
||||
|
||||
if (!this.hasLoadedCommon) {
|
||||
this.sight.common = {
|
||||
...this.sight.common,
|
||||
runInAction(() => {
|
||||
this.sight[language] = {
|
||||
...this.sight[language],
|
||||
...data,
|
||||
};
|
||||
this.hasLoadedCommon = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.hasLoadedCommon) {
|
||||
this.sight.common = {
|
||||
...this.sight.common,
|
||||
...data,
|
||||
};
|
||||
this.hasLoadedCommon = true;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
updateLeftInfo = (language: Language, heading: string, body: string) => {
|
||||
@@ -168,6 +175,8 @@ class EditSightStore {
|
||||
|
||||
clearSightInfo = () => {
|
||||
this.needLeaveAgree = false;
|
||||
this.hasLoadedCommon = false;
|
||||
this.isLoading = false;
|
||||
this.sight = {
|
||||
common: {
|
||||
id: 0,
|
||||
|
||||
@@ -3,3 +3,4 @@ export * from "./BackButton";
|
||||
export * from "./Modal";
|
||||
export * from "./CoordinatesInput";
|
||||
export * from "./AnimatedCircleButton";
|
||||
export * from "./LoadingSpinner";
|
||||
|
||||
@@ -10,23 +10,25 @@ import { observer } from "mobx-react-lite";
|
||||
import { useState, DragEvent, useRef } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
interface MediaAreaProps {
|
||||
articleId: number;
|
||||
mediaIds: { id: string; media_type: number; filename: string }[];
|
||||
deleteMedia: (id: number, media_id: string) => void;
|
||||
onFilesDrop?: (files: File[]) => void;
|
||||
setSelectMediaDialogOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export const MediaArea = observer(
|
||||
({
|
||||
articleId,
|
||||
mediaIds,
|
||||
deleteMedia,
|
||||
onFilesDrop, // 👈 Проп для обработки загруженных файлов
|
||||
onFilesDrop,
|
||||
setSelectMediaDialogOpen,
|
||||
}: {
|
||||
articleId: number;
|
||||
mediaIds: { id: string; media_type: number; filename: string }[];
|
||||
deleteMedia: (id: number, media_id: string) => void;
|
||||
onFilesDrop?: (files: File[]) => void;
|
||||
setSelectMediaDialogOpen: (open: boolean) => void;
|
||||
}) => {
|
||||
}: MediaAreaProps) => {
|
||||
const [mediaModal, setMediaModal] = useState<boolean>(false);
|
||||
const [mediaId, setMediaId] = useState<string>("");
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleMediaModal = (mediaId: string) => {
|
||||
@@ -34,23 +36,29 @@ export const MediaArea = observer(
|
||||
setMediaId(mediaId);
|
||||
};
|
||||
|
||||
const processFiles = (files: File[]) => {
|
||||
if (!files.length || !onFilesDrop) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
onFilesDrop(validFiles);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
if (files.length && onFilesDrop) {
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
onFilesDrop(validFiles);
|
||||
}
|
||||
}
|
||||
processFiles(files);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
|
||||
@@ -68,19 +76,11 @@ export const MediaArea = observer(
|
||||
|
||||
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
if (files.length && onFilesDrop) {
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
processFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
onFilesDrop(validFiles);
|
||||
}
|
||||
if (event.target) {
|
||||
event.target.value = "";
|
||||
}
|
||||
// Сбрасываем значение input, чтобы можно было выбрать тот же файл снова
|
||||
event.target.value = "";
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -96,7 +96,7 @@ export const MediaArea = observer(
|
||||
<Box className="w-full flex flex-col items-center justify-center border rounded-md p-4">
|
||||
<div className="w-full flex flex-col items-center justify-center">
|
||||
<div
|
||||
className={`w-full h-40 flex flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 ${
|
||||
className={`w-full h-40 flex flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 transition-colors ${
|
||||
isDragging ? "bg-blue-100 border-blue-400" : ""
|
||||
}`}
|
||||
onDrop={handleDrop}
|
||||
@@ -105,9 +105,11 @@ export const MediaArea = observer(
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Upload size={32} className="mb-2" />
|
||||
Перетащите медиа файлы сюда или нажмите для выбора
|
||||
<span className="text-center">
|
||||
Перетащите медиа файлы сюда или нажмите для выбора
|
||||
</span>
|
||||
</div>
|
||||
<div>или</div>
|
||||
<div className="my-2">или</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
@@ -117,33 +119,38 @@ export const MediaArea = observer(
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="w-full flex flex-start flex-wrap gap-2 mt-4 py-10">
|
||||
{mediaIds.map((m) => (
|
||||
<button
|
||||
className="relative w-20 h-20"
|
||||
key={m.id}
|
||||
onClick={() => handleMediaModal(m.id)}
|
||||
>
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: m.id,
|
||||
media_type: m.media_type,
|
||||
filename: m.filename,
|
||||
}}
|
||||
height="40px"
|
||||
/>
|
||||
{mediaIds.length > 0 && (
|
||||
<div className="w-full flex flex-start flex-wrap gap-2 mt-4 py-10">
|
||||
{mediaIds.map((m) => (
|
||||
<button
|
||||
className="absolute top-2 right-2"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteMedia(articleId, m.id);
|
||||
}}
|
||||
className="relative w-20 h-20"
|
||||
key={m.id}
|
||||
onClick={() => handleMediaModal(m.id)}
|
||||
type="button"
|
||||
>
|
||||
<X size={16} color="red" />
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: m.id,
|
||||
media_type: m.media_type,
|
||||
filename: m.filename,
|
||||
}}
|
||||
height="40px"
|
||||
/>
|
||||
<button
|
||||
className="absolute top-2 right-2 bg-white rounded-full p-1 shadow-md hover:shadow-lg transition-shadow"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteMedia(articleId, m.id);
|
||||
}}
|
||||
type="button"
|
||||
aria-label="Удалить медиа"
|
||||
>
|
||||
<X size={16} color="red" />
|
||||
</button>
|
||||
</button>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<PreviewMediaDialog
|
||||
|
||||
@@ -11,52 +11,72 @@ import { observer } from "mobx-react-lite";
|
||||
import { useState, DragEvent, useRef } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
type ContextType =
|
||||
| "sight"
|
||||
| "city"
|
||||
| "carrier"
|
||||
| "country"
|
||||
| "vehicle"
|
||||
| "station";
|
||||
|
||||
interface MediaAreaForSightProps {
|
||||
onFilesDrop?: (files: File[]) => void;
|
||||
onFinishUpload?: (mediaId: string) => void;
|
||||
contextObjectName?: string;
|
||||
contextType?: ContextType;
|
||||
isArticle?: boolean;
|
||||
articleName?: string;
|
||||
}
|
||||
|
||||
export const MediaAreaForSight = observer(
|
||||
({
|
||||
onFilesDrop, // 👈 Проп для обработки загруженных файлов
|
||||
onFilesDrop,
|
||||
onFinishUpload,
|
||||
contextObjectName,
|
||||
contextType,
|
||||
isArticle,
|
||||
articleName,
|
||||
}: {
|
||||
onFilesDrop?: (files: File[]) => void;
|
||||
onFinishUpload?: (mediaId: string) => void;
|
||||
contextObjectName?: string;
|
||||
contextType?:
|
||||
| "sight"
|
||||
| "city"
|
||||
| "carrier"
|
||||
| "country"
|
||||
| "vehicle"
|
||||
| "station";
|
||||
isArticle?: boolean;
|
||||
articleName?: string;
|
||||
}) => {
|
||||
const [selectMediaDialogOpen, setSelectMediaDialogOpen] = useState(false);
|
||||
const [uploadMediaDialogOpen, setUploadMediaDialogOpen] = useState(false);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
}: MediaAreaForSightProps) => {
|
||||
const [selectMediaDialogOpen, setSelectMediaDialogOpen] =
|
||||
useState<boolean>(false);
|
||||
const [uploadMediaDialogOpen, setUploadMediaDialogOpen] =
|
||||
useState<boolean>(false);
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { setFileToUpload } = editSightStore;
|
||||
|
||||
const processFiles = (files: File[]) => {
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error: string) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
// Сохраняем первый файл для загрузки
|
||||
setFileToUpload(validFiles[0]);
|
||||
|
||||
// Вызываем колбэк, если он передан
|
||||
if (onFilesDrop) {
|
||||
onFilesDrop(validFiles);
|
||||
}
|
||||
|
||||
// Открываем диалог загрузки
|
||||
setUploadMediaDialogOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragging(false);
|
||||
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
if (files.length) {
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error: string) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0 && onFilesDrop) {
|
||||
setFileToUpload(validFiles[0]);
|
||||
setUploadMediaDialogOpen(true);
|
||||
}
|
||||
}
|
||||
processFiles(files);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
|
||||
@@ -74,22 +94,12 @@ export const MediaAreaForSight = observer(
|
||||
|
||||
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
if (files.length) {
|
||||
const { validFiles, errors } = filterValidFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error: string) => toast.error(error));
|
||||
}
|
||||
|
||||
if (validFiles.length > 0 && onFilesDrop) {
|
||||
setFileToUpload(validFiles[0]);
|
||||
onFilesDrop(validFiles);
|
||||
setUploadMediaDialogOpen(true);
|
||||
}
|
||||
}
|
||||
processFiles(files);
|
||||
|
||||
// Сбрасываем значение input, чтобы можно было выбрать тот же файл снова
|
||||
event.target.value = "";
|
||||
if (event.target) {
|
||||
event.target.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -105,7 +115,7 @@ export const MediaAreaForSight = observer(
|
||||
<Box className="w-full flex flex-col items-center justify-center border rounded-md p-4">
|
||||
<div className="w-full flex flex-col items-center justify-center">
|
||||
<div
|
||||
className={`w-full h-40 flex text-center flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 ${
|
||||
className={`w-full h-40 flex flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 transition-colors ${
|
||||
isDragging ? "bg-blue-100 border-blue-400" : ""
|
||||
}`}
|
||||
onDrop={handleDrop}
|
||||
@@ -114,9 +124,11 @@ export const MediaAreaForSight = observer(
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Upload size={32} className="mb-2" />
|
||||
Перетащите медиа файлы сюда или нажмите для выбора
|
||||
<span className="text-center">
|
||||
Перетащите медиа файлы сюда или нажмите для выбора
|
||||
</span>
|
||||
</div>
|
||||
<div>или</div>
|
||||
<div className="my-2">или</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
|
||||
@@ -127,8 +127,8 @@ export function MediaViewer({
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
width={width ? width : "500px"}
|
||||
height={height ? height : "300px"}
|
||||
width={fullWidth ? "100%" : width ? width : "500px"}
|
||||
height={fullHeight ? "100%" : height ? height : "300px"}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -434,49 +434,61 @@ export const CreateRightTab = observer(
|
||||
</Box>
|
||||
) : type === "media" ? (
|
||||
<Box className="w-[80%] border border-gray-300 rounded-2xl relative flex items-center justify-center">
|
||||
{sight.preview_media && (
|
||||
<>
|
||||
{type === "media" && (
|
||||
<Box className="w-[80%] h-full rounded-2xl relative flex items-center justify-center">
|
||||
{previewMedia && (
|
||||
<>
|
||||
<Box className="absolute top-4 right-4 z-10">
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center z-10"
|
||||
onClick={handleUnlinkPreviewMedia}
|
||||
>
|
||||
<X size={20} color="red" />
|
||||
</button>
|
||||
</Box>
|
||||
<>
|
||||
{type === "media" && (
|
||||
<Box className="w-[80%] h-full rounded-2xl relative flex items-center justify-center">
|
||||
{previewMedia && (
|
||||
<>
|
||||
<Box className="absolute top-4 right-4 z-10">
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center z-10"
|
||||
onClick={handleUnlinkPreviewMedia}
|
||||
>
|
||||
<X size={20} color="red" />
|
||||
</button>
|
||||
</Box>
|
||||
|
||||
<Box className="w-1/2 h-1/2">
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: previewMedia.id || "",
|
||||
media_type: previewMedia.media_type,
|
||||
filename: previewMedia.filename || "",
|
||||
}}
|
||||
fullWidth
|
||||
fullHeight
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!previewMedia && (
|
||||
<MediaAreaForSight
|
||||
onFinishUpload={(mediaId) => {
|
||||
linkPreviewMedia(mediaId);
|
||||
}}
|
||||
onFilesDrop={() => {}}
|
||||
contextObjectName={sight[language].name}
|
||||
contextType="sight"
|
||||
isArticle={false}
|
||||
/>
|
||||
)}
|
||||
<Box className="w-1/2 h-1/2">
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: previewMedia.id || "",
|
||||
media_type: previewMedia.media_type,
|
||||
filename: previewMedia.filename || "",
|
||||
}}
|
||||
fullWidth
|
||||
fullHeight
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{!previewMedia && (
|
||||
<Box className="w-full h-full flex justify-center items-center">
|
||||
<Box
|
||||
sx={{
|
||||
maxWidth: "500px",
|
||||
maxHeight: "100%",
|
||||
display: "flex",
|
||||
flexGrow: 1,
|
||||
margin: "0 auto",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<MediaAreaForSight
|
||||
onFinishUpload={(mediaId) => {
|
||||
linkPreviewMedia(mediaId);
|
||||
}}
|
||||
onFilesDrop={() => {}}
|
||||
contextObjectName={sight[language].name}
|
||||
contextType="sight"
|
||||
isArticle={false}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
</Box>
|
||||
) : (
|
||||
<Box className="w-[80%] h-[70vh] border border-gray-300 rounded-2xl p-3 flex justify-center items-center">
|
||||
|
||||
@@ -415,21 +415,12 @@ export const RightWidgetTab = observer(
|
||||
media_type: previewMedia.media_type,
|
||||
filename: previewMedia.filename || "",
|
||||
}}
|
||||
fullWidth
|
||||
fullHeight
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
{!previewMedia && (
|
||||
<MediaAreaForSight
|
||||
onFinishUpload={(mediaId) => {
|
||||
linkPreviewMedia(mediaId);
|
||||
}}
|
||||
onFilesDrop={() => {}}
|
||||
contextObjectName={sight[language].name}
|
||||
contextType="sight"
|
||||
isArticle={false}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user