diff --git a/src/pages/Article/ArticlePreviewPage/index.tsx b/src/pages/Article/ArticlePreviewPage/index.tsx index bce26ed..40b8953 100644 --- a/src/pages/Article/ArticlePreviewPage/index.tsx +++ b/src/pages/Article/ArticlePreviewPage/index.tsx @@ -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 ( + + + + ); + } + return ( <>
diff --git a/src/pages/Carrier/CarrierEditPage/index.tsx b/src/pages/Carrier/CarrierEditPage/index.tsx index ff6ed55..0b17050 100644 --- a/src/pages/Carrier/CarrierEditPage/index.tsx +++ b/src/pages/Carrier/CarrierEditPage/index.tsx @@ -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 ( + + + + ); + } + return ( diff --git a/src/pages/City/CityEditPage/index.tsx b/src/pages/City/CityEditPage/index.tsx index dcccc3f..b5a274e 100644 --- a/src/pages/City/CityEditPage/index.tsx +++ b/src/pages/City/CityEditPage/index.tsx @@ -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 ( + + + + ); + } + return ( diff --git a/src/pages/Country/CountryEditPage/index.tsx b/src/pages/Country/CountryEditPage/index.tsx index 5802069..fbfda84 100644 --- a/src/pages/Country/CountryEditPage/index.tsx +++ b/src/pages/Country/CountryEditPage/index.tsx @@ -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 ( + + + + ); + } + return ( diff --git a/src/pages/EditSightPage/index.tsx b/src/pages/EditSightPage/index.tsx index 48c3f42..22549be 100644 --- a/src/pages/EditSightPage/index.tsx +++ b/src/pages/EditSightPage/index.tsx @@ -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(() => { - {sight.common.id !== 0 && ( -
- - - -
+ {isLoadingData ? ( + + + + ) : ( + sight.common.id !== 0 && ( +
+ + + +
+ ) )} {blocker.state === "blocked" ? : null} diff --git a/src/pages/Media/MediaEditPage/index.tsx b/src/pages/Media/MediaEditPage/index.tsx index 26237f3..f2136f2 100644 --- a/src/pages/Media/MediaEditPage/index.tsx +++ b/src/pages/Media/MediaEditPage/index.tsx @@ -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 ( - - + + ); } diff --git a/src/pages/Route/RouteEditPage/index.tsx b/src/pages/Route/RouteEditPage/index.tsx index 5a03801..d78d9fd 100644 --- a/src/pages/Route/RouteEditPage/index.tsx +++ b/src/pages/Route/RouteEditPage/index.tsx @@ -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 ( + + + + ); + } + return (
diff --git a/src/pages/Station/StationEditPage/index.tsx b/src/pages/Station/StationEditPage/index.tsx index 69d3275..d1f28eb 100644 --- a/src/pages/Station/StationEditPage/index.tsx +++ b/src/pages/Station/StationEditPage/index.tsx @@ -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 ( + + + + ); + } + return ( diff --git a/src/pages/Station/StationPreviewPage/index.tsx b/src/pages/Station/StationPreviewPage/index.tsx index d45dc72..6abfa92 100644 --- a/src/pages/Station/StationPreviewPage/index.tsx +++ b/src/pages/Station/StationPreviewPage/index.tsx @@ -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 ( + + + + ); + } + return ( diff --git a/src/pages/User/UserEditPage/index.tsx b/src/pages/User/UserEditPage/index.tsx index b6def48..b5cd7a8 100644 --- a/src/pages/User/UserEditPage/index.tsx +++ b/src/pages/User/UserEditPage/index.tsx @@ -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 ( + + + + ); + } + return (
diff --git a/src/shared/store/EditSightStore/index.tsx b/src/shared/store/EditSightStore/index.tsx index 5c6ab82..291df55 100644 --- a/src/shared/store/EditSightStore/index.tsx +++ b/src/shared/store/EditSightStore/index.tsx @@ -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, diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts index 4728641..1adb123 100644 --- a/src/shared/ui/index.ts +++ b/src/shared/ui/index.ts @@ -3,3 +3,4 @@ export * from "./BackButton"; export * from "./Modal"; export * from "./CoordinatesInput"; export * from "./AnimatedCircleButton"; +export * from "./LoadingSpinner"; diff --git a/src/widgets/MediaArea/index.tsx b/src/widgets/MediaArea/index.tsx index f0696bb..6aaeb48 100644 --- a/src/widgets/MediaArea/index.tsx +++ b/src/widgets/MediaArea/index.tsx @@ -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(false); const [mediaId, setMediaId] = useState(""); - const [isDragging, setIsDragging] = useState(false); + const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(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) => { 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) => { @@ -68,19 +76,11 @@ export const MediaArea = observer( const handleFileSelect = (event: React.ChangeEvent) => { 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(
- Перетащите медиа файлы сюда или нажмите для выбора + + Перетащите медиа файлы сюда или нажмите для выбора +
-
или
+
или
-
- {mediaIds.map((m) => ( - - - ))} -
+ ))} +
+ )} 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(false); + const [uploadMediaDialogOpen, setUploadMediaDialogOpen] = + useState(false); + const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(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) => { 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) => { @@ -74,22 +94,12 @@ export const MediaAreaForSight = observer( const handleFileSelect = (event: React.ChangeEvent) => { 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(
- Перетащите медиа файлы сюда или нажмите для выбора + + Перетащите медиа файлы сюда или нажмите для выбора +
-
или
+
или
- + <> + {type === "media" && ( + + {previewMedia && ( + <> + + + - - - - - )} - - )} - - )} - {!previewMedia && ( - { - linkPreviewMedia(mediaId); - }} - onFilesDrop={() => {}} - contextObjectName={sight[language].name} - contextType="sight" - isArticle={false} - /> - )} + + + + + )} + + {!previewMedia && ( + + + { + linkPreviewMedia(mediaId); + }} + onFilesDrop={() => {}} + contextObjectName={sight[language].name} + contextType="sight" + isArticle={false} + /> + + + )} + + )} + ) : ( diff --git a/src/widgets/SightTabs/RightWidgetTab/index.tsx b/src/widgets/SightTabs/RightWidgetTab/index.tsx index 02432d7..234e2c7 100644 --- a/src/widgets/SightTabs/RightWidgetTab/index.tsx +++ b/src/widgets/SightTabs/RightWidgetTab/index.tsx @@ -415,21 +415,12 @@ export const RightWidgetTab = observer( media_type: previewMedia.media_type, filename: previewMedia.filename || "", }} + fullWidth + fullHeight /> )} - {!previewMedia && ( - { - linkPreviewMedia(mediaId); - }} - onFilesDrop={() => {}} - contextObjectName={sight[language].name} - contextType="sight" - isArticle={false} - /> - )} )}