feat: Add scale
on group click, add cache for map entities
, fix map preview loading
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import { useTransform } from "./TransformContext";
|
||||
import { coordinatesToLocal, localToCoordinates } from "./utils";
|
||||
import { SCALE_FACTOR } from "./Constants";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
export function RightSidebar() {
|
||||
const {
|
||||
@ -360,8 +361,14 @@ export function RightSidebar() {
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
sx={{ mt: 2 }}
|
||||
onClick={() => {
|
||||
saveChanges();
|
||||
onClick={async () => {
|
||||
try {
|
||||
await saveChanges();
|
||||
toast.success("Изменения сохранены");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Ошибка при сохранении изменений");
|
||||
}
|
||||
}}
|
||||
>
|
||||
Сохранить изменения
|
||||
|
@ -26,6 +26,7 @@ import { Sight } from "./Sight";
|
||||
import { SightData } from "./types";
|
||||
import { Station } from "./Station";
|
||||
import { UP_SCALE } from "./Constants";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
|
||||
extend({
|
||||
Container,
|
||||
@ -36,13 +37,27 @@ extend({
|
||||
Text,
|
||||
});
|
||||
|
||||
const Loading = () => {
|
||||
const { isRouteLoading, isStationLoading, isSightLoading } = useMapData();
|
||||
|
||||
if (isRouteLoading || isStationLoading || isSightLoading) {
|
||||
return (
|
||||
<div className="fixed flex z-1 items-center justify-center h-screen w-screen bg-[#111]">
|
||||
<CircularProgress />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
export const RoutePreview = () => {
|
||||
const { routeData, stationData, sightData } = useMapData();
|
||||
return (
|
||||
<MapDataProvider>
|
||||
<TransformProvider>
|
||||
<Stack direction="row" height="100vh" width="100vw" overflow="hidden">
|
||||
<LanguageSwitcher />
|
||||
|
||||
{routeData && stationData && sightData ? <LanguageSwitcher /> : null}
|
||||
<Loading />
|
||||
<LeftSidebar />
|
||||
<Stack direction="row" flex={1} position="relative" height="100%">
|
||||
<RouteMap />
|
||||
@ -145,8 +160,7 @@ export const RouteMap = observer(() => {
|
||||
]);
|
||||
|
||||
if (!routeData || !stationData || !sightData) {
|
||||
console.error("routeData, stationData or sightData is null");
|
||||
return <div>Loading...</div>;
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -81,6 +81,7 @@ export const UploadMediaDialog = observer(
|
||||
const [availableMediaTypes, setAvailableMediaTypes] = useState<number[]>(
|
||||
[]
|
||||
);
|
||||
const [isPreviewLoaded, setIsPreviewLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialFile) {
|
||||
@ -207,6 +208,7 @@ export const UploadMediaDialog = observer(
|
||||
useEffect(() => {
|
||||
if (mediaFile) {
|
||||
setMediaUrl(URL.createObjectURL(mediaFile as Blob));
|
||||
setIsPreviewLoaded(false); // Сбрасываем состояние загрузки при смене файла
|
||||
}
|
||||
}, [mediaFile]);
|
||||
|
||||
@ -326,8 +328,22 @@ export const UploadMediaDialog = observer(
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "100%",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{!isPreviewLoaded && mediaUrl && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
)}
|
||||
{mediaType == 2 && mediaUrl && (
|
||||
<video
|
||||
src={mediaUrl}
|
||||
@ -336,10 +352,16 @@ export const UploadMediaDialog = observer(
|
||||
loop
|
||||
controls
|
||||
style={{ maxWidth: "100%", maxHeight: "100%" }}
|
||||
onLoadedData={() => setIsPreviewLoaded(true)}
|
||||
onError={() => setIsPreviewLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
{mediaType === 6 && mediaUrl && (
|
||||
<ModelViewer3D fileUrl={mediaUrl} height="100%" />
|
||||
<ModelViewer3D
|
||||
fileUrl={mediaUrl}
|
||||
height="100%"
|
||||
onLoad={() => setIsPreviewLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
{mediaType !== 6 && mediaType !== 2 && mediaUrl && (
|
||||
<img
|
||||
@ -349,6 +371,8 @@ export const UploadMediaDialog = observer(
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
onLoad={() => setIsPreviewLoaded(true)}
|
||||
onError={() => setIsPreviewLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
</Paper>
|
||||
@ -370,9 +394,17 @@ export const UploadMediaDialog = observer(
|
||||
)
|
||||
}
|
||||
onClick={handleSave}
|
||||
disabled={isLoading || (!mediaName && !mediaFilename)}
|
||||
disabled={
|
||||
isLoading ||
|
||||
(!mediaName && !mediaFilename) ||
|
||||
!isPreviewLoaded
|
||||
}
|
||||
>
|
||||
{isLoading ? "Сохранение..." : "Сохранить"}
|
||||
{isLoading
|
||||
? "Сохранение..."
|
||||
: !isPreviewLoaded
|
||||
? "Загрузка превью..."
|
||||
: "Сохранить"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -97,15 +97,19 @@ class SightsStore {
|
||||
city: number,
|
||||
coordinates: { latitude: number; longitude: number }
|
||||
) => {
|
||||
const id = (
|
||||
await authInstance.post("/sight", {
|
||||
const response = await authInstance.post("/sight", {
|
||||
name: this.createSight[languageStore.language].name,
|
||||
address: this.createSight[languageStore.language].address,
|
||||
city_id: city,
|
||||
latitude: coordinates.latitude,
|
||||
longitude: coordinates.longitude,
|
||||
})
|
||||
).data.id;
|
||||
});
|
||||
|
||||
runInAction(() => {
|
||||
this.sights.push(response.data);
|
||||
});
|
||||
|
||||
const id = response.data.id;
|
||||
|
||||
const anotherLanguages = ["ru", "en", "zh"].filter(
|
||||
(language) => language !== languageStore.language
|
||||
|
@ -51,7 +51,7 @@ export const LanguageSwitcher = observer(() => {
|
||||
key={lang}
|
||||
onClick={() => handleLanguageChange(lang)}
|
||||
variant={"contained"} // Highlight the active language
|
||||
color={language === lang ? "primary" : "secondary"}
|
||||
color={language === lang ? "primary" : "inherit"}
|
||||
sx={{ minWidth: "60px" }} // Give buttons a consistent width
|
||||
>
|
||||
{getLanguageLabel(lang)}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import React from "react";
|
||||
import { Stage, useGLTF } from "@react-three/drei";
|
||||
import { Canvas } from "@react-three/fiber";
|
||||
import { OrbitControls } from "@react-three/drei";
|
||||
@ -5,12 +6,21 @@ import { OrbitControls } from "@react-three/drei";
|
||||
export const ModelViewer3D = ({
|
||||
fileUrl,
|
||||
height = "100%",
|
||||
onLoad,
|
||||
}: {
|
||||
fileUrl: string;
|
||||
height: string;
|
||||
onLoad?: () => void;
|
||||
}) => {
|
||||
const { scene } = useGLTF(fileUrl);
|
||||
|
||||
// Вызываем onLoad когда модель загружена
|
||||
React.useEffect(() => {
|
||||
if (onLoad) {
|
||||
onLoad();
|
||||
}
|
||||
}, [scene, onLoad]);
|
||||
|
||||
return (
|
||||
<Canvas style={{ width: "100%", height: height }}>
|
||||
<ambientLight />
|
||||
|
Reference in New Issue
Block a user