feature/webgl-preview-update #21
@@ -23,6 +23,7 @@ const App = observer(() => {
|
|||||||
loadingStatus,
|
loadingStatus,
|
||||||
loadingProgress,
|
loadingProgress,
|
||||||
context,
|
context,
|
||||||
|
carrier,
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
setLoadingStatus,
|
setLoadingStatus,
|
||||||
setLoadingProgress,
|
setLoadingProgress,
|
||||||
@@ -172,6 +173,7 @@ const App = observer(() => {
|
|||||||
loadingStatus={loadingStatus}
|
loadingStatus={loadingStatus}
|
||||||
loadingProgress={loadingProgress}
|
loadingProgress={loadingProgress}
|
||||||
onToggleDebug={() => setIsDebugVisible((prev) => !prev)}
|
onToggleDebug={() => setIsDebugVisible((prev) => !prev)}
|
||||||
|
videoId={carrier?.video_preview}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ export type GetRouteResponse = {
|
|||||||
route_sys_number: string;
|
route_sys_number: string;
|
||||||
scale_max: number;
|
scale_max: number;
|
||||||
scale_min: number;
|
scale_min: number;
|
||||||
video_preview: string;
|
|
||||||
video_timer?: number;
|
video_timer?: number;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
icon_size?: number;
|
icon_size?: number;
|
||||||
@@ -77,6 +76,8 @@ export type GetCarrierResponse = {
|
|||||||
full_name: string;
|
full_name: string;
|
||||||
id: number;
|
id: number;
|
||||||
logo: string;
|
logo: string;
|
||||||
|
preview_media?: string;
|
||||||
|
video_preview?: string;
|
||||||
short_name: string;
|
short_name: string;
|
||||||
slogan: string;
|
slogan: string;
|
||||||
main_color?: string;
|
main_color?: string;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import "../styles/Loader.css";
|
import "../styles/Loader.css";
|
||||||
|
import { getMediaUrl } from "../api/apiConfig";
|
||||||
|
|
||||||
const loaderVideoPath = new URL("../assets/video/taganai.mp4", import.meta.url)
|
const loaderVideoPath = new URL("../assets/video/taganai.mp4", import.meta.url)
|
||||||
.href;
|
.href;
|
||||||
@@ -9,8 +10,14 @@ const Loader = ({
|
|||||||
loadingStatus = null,
|
loadingStatus = null,
|
||||||
loadingProgress = null,
|
loadingProgress = null,
|
||||||
onToggleDebug,
|
onToggleDebug,
|
||||||
|
videoId = null,
|
||||||
}) => {
|
}) => {
|
||||||
const [showLoadingInfo, setShowLoadingInfo] = useState(false);
|
const [showLoadingInfo, setShowLoadingInfo] = useState(false);
|
||||||
|
const [isCustomVideoError, setIsCustomVideoError] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsCustomVideoError(false);
|
||||||
|
}, [videoId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = (event) => {
|
||||||
@@ -55,7 +62,12 @@ const Loader = ({
|
|||||||
loop
|
loop
|
||||||
muted
|
muted
|
||||||
playsInline
|
playsInline
|
||||||
src={loaderVideoPath}
|
src={
|
||||||
|
videoId && !isCustomVideoError
|
||||||
|
? getMediaUrl(videoId)
|
||||||
|
: loaderVideoPath
|
||||||
|
}
|
||||||
|
onError={() => setIsCustomVideoError(true)}
|
||||||
alt="Loading"
|
alt="Loading"
|
||||||
className="error-gif"
|
className="error-gif"
|
||||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ import StationsList from "./StationsList";
|
|||||||
import LeftWidget from "./LeftWidget";
|
import LeftWidget from "./LeftWidget";
|
||||||
import { apiStore } from "../../api/ApiStore/store";
|
import { apiStore } from "../../api/ApiStore/store";
|
||||||
import { getMediaUrl } from "../../api/apiConfig";
|
import { getMediaUrl } from "../../api/apiConfig";
|
||||||
import defaultCrest from "../../assets/images/Герб.png";
|
|
||||||
|
|
||||||
const SideMenu = observer(({ onMenuToggle }) => {
|
const SideMenu = observer(({ onMenuToggle }) => {
|
||||||
const {
|
const {
|
||||||
carrier,
|
carrier,
|
||||||
city,
|
|
||||||
route,
|
route,
|
||||||
getArticle,
|
getArticle,
|
||||||
sightArticles,
|
sightArticles,
|
||||||
@@ -33,6 +31,7 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
const [isStationOpen, openStation] = useState(false);
|
const [isStationOpen, openStation] = useState(false);
|
||||||
const [isWidgetOpen, openWidget] = useState(false);
|
const [isWidgetOpen, openWidget] = useState(false);
|
||||||
const [isWeatherVisible, setIsWeatherVisible] = useState(true);
|
const [isWeatherVisible, setIsWeatherVisible] = useState(true);
|
||||||
|
const [isPreviewMediaError, setIsPreviewMediaError] = useState(false);
|
||||||
const [isLeftWidgetVisible, setIsLeftWidgetVisible] = useState(false);
|
const [isLeftWidgetVisible, setIsLeftWidgetVisible] = useState(false);
|
||||||
const [localSelectedSightId, setLocalSelectedSightId] = useState(null);
|
const [localSelectedSightId, setLocalSelectedSightId] = useState(null);
|
||||||
const [isSightsAnimating, setIsSightsAnimating] = useState(false);
|
const [isSightsAnimating, setIsSightsAnimating] = useState(false);
|
||||||
@@ -186,27 +185,12 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
}
|
}
|
||||||
}, [isLeftWidgetVisible]);
|
}, [isLeftWidgetVisible]);
|
||||||
|
|
||||||
const [designData, setDesignData] = useState(null);
|
|
||||||
const [routeData, setRouteData] = useState(null);
|
const [routeData, setRouteData] = useState(null);
|
||||||
const [isLangMenuOpen, setIsLangMenuOpen] = useState(false);
|
const [isLangMenuOpen, setIsLangMenuOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchCarrierAndCrest() {
|
setIsPreviewMediaError(false);
|
||||||
try {
|
}, [carrier?.preview_media]);
|
||||||
const carrierPath = carrier.logo ? getMediaUrl(carrier.logo) : null;
|
|
||||||
const cityPath = city.arms ? getMediaUrl(city.arms) : null;
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
carrierPath: carrierPath,
|
|
||||||
creastPath: cityPath,
|
|
||||||
};
|
|
||||||
setDesignData(response);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Ошибка в получении данных герба и перевозчика:", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetchCarrierAndCrest();
|
|
||||||
}, [contextData?.routeId, isGeolocationLoading, selectedLanguage]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isGeolocationLoading || !contextData?.routeId) {
|
if (isGeolocationLoading || !contextData?.routeId) {
|
||||||
@@ -415,14 +399,6 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
"background 0.3s ease, backdrop-filter 0.3s ease, box-shadow 0.3s ease",
|
"background 0.3s ease, backdrop-filter 0.3s ease, box-shadow 0.3s ease",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
|
||||||
className="side-menu-crest"
|
|
||||||
src={designData?.creastPath || defaultCrest}
|
|
||||||
alt="Герб"
|
|
||||||
/>
|
|
||||||
{carrier?.slogan && (
|
|
||||||
<div className="side-menu-label">{carrier.slogan}</div>
|
|
||||||
)}
|
|
||||||
{shouldRenderSights && (
|
{shouldRenderSights && (
|
||||||
<SightsList
|
<SightsList
|
||||||
ref={sightsListRef}
|
ref={sightsListRef}
|
||||||
@@ -606,19 +582,16 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
: "#EveryoneOnTheWay"} */}
|
: "#EveryoneOnTheWay"} */}
|
||||||
</div>
|
</div>
|
||||||
<div className="side-menu-bottom-section">
|
<div className="side-menu-bottom-section">
|
||||||
<div className="side-menu-carrier-block">
|
<img
|
||||||
{designData?.carrierPath && (
|
className="side-menu-bottom-photo"
|
||||||
<img
|
src={
|
||||||
className="carrier-logo"
|
carrier?.preview_media && !isPreviewMediaError
|
||||||
src={designData?.carrierPath}
|
? getMediaUrl(carrier.preview_media)
|
||||||
alt="ГЭТ - Электротранспорт Санкт-Петербурга"
|
: sideMenuPhoto
|
||||||
/>
|
}
|
||||||
)}
|
onError={() => setIsPreviewMediaError(true)}
|
||||||
{carrier?.full_name && (
|
alt=""
|
||||||
<div className="side-menu-slogan">{carrier.short_name}</div>
|
/>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<img className="side-menu-bottom-photo" src={sideMenuPhoto} alt="" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="side-menu-control-panel">
|
<div className="side-menu-control-panel">
|
||||||
|
|||||||
@@ -16,17 +16,6 @@
|
|||||||
var(--carrier-left, #006f3a);
|
var(--carrier-left, #006f3a);
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-menu-label {
|
|
||||||
margin-top: 10px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 15px;
|
|
||||||
padding: 0 20px;
|
|
||||||
align-self: flex-start;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 150%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.appeal-button {
|
.appeal-button {
|
||||||
color: black;
|
color: black;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
@@ -66,24 +55,6 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-menu-carrier-block {
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.carrier-logo {
|
|
||||||
width: 170px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-menu-slogan {
|
|
||||||
margin-top: 4px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 16px;
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 150%;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-menu-bottom-photo {
|
.side-menu-bottom-photo {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
@@ -284,12 +255,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-menu-crest {
|
|
||||||
width: 170px;
|
|
||||||
align-self: flex-start;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-menu-control-lang-open {
|
.side-menu-control-lang-open {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Paper,
|
|
||||||
TextField,
|
TextField,
|
||||||
Select,
|
Select,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
@@ -24,9 +23,10 @@ import {
|
|||||||
SelectMediaDialog,
|
SelectMediaDialog,
|
||||||
UploadMediaDialog,
|
UploadMediaDialog,
|
||||||
PreviewMediaDialog,
|
PreviewMediaDialog,
|
||||||
|
editSightStore,
|
||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { ImageUploadCard, LanguageSwitcher } from "@widgets";
|
import { ImageUploadCard, LanguageSwitcher, VideoPreviewCard } from "@widgets";
|
||||||
|
|
||||||
type ColorFields = { main_color: string; left_color: string; right_color: string };
|
type ColorFields = { main_color: string; left_color: string; right_color: string };
|
||||||
|
|
||||||
@@ -80,18 +80,29 @@ const ColorPickerField = ({
|
|||||||
|
|
||||||
export const CarrierCreatePage = observer(() => {
|
export const CarrierCreatePage = observer(() => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { createCarrierData, setCreateCarrierData } = carrierStore;
|
const {
|
||||||
|
createCarrierData,
|
||||||
|
setCreateCarrierData,
|
||||||
|
setCreateCarrierMedia,
|
||||||
|
} = carrierStore;
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
const canReadCities = authStore.canRead("cities");
|
const canReadCities = authStore.canRead("cities");
|
||||||
const { selectedCityId, selectedCity } = useSelectedCity();
|
const { selectedCityId, selectedCity } = useSelectedCity();
|
||||||
const [selectedMediaId, setSelectedMediaId] = useState<string | null>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isSelectMediaOpen, setIsSelectMediaOpen] = useState(false);
|
const [isSelectMediaOpen, setIsSelectMediaOpen] = useState(false);
|
||||||
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
||||||
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
||||||
const [mediaId, setMediaId] = useState("");
|
const [mediaId, setMediaId] = useState("");
|
||||||
|
const [activeMediaField, setActiveMediaField] = useState<
|
||||||
|
"preview_media" | "video_preview"
|
||||||
|
>("preview_media");
|
||||||
const [activeMenuType, setActiveMenuType] = useState<
|
const [activeMenuType, setActiveMenuType] = useState<
|
||||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
| "thumbnail"
|
||||||
|
| "watermark_lu"
|
||||||
|
| "watermark_rd"
|
||||||
|
| "image"
|
||||||
|
| "video_preview"
|
||||||
|
| null
|
||||||
>(null);
|
>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,12 +148,16 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
selectedCityId,
|
selectedCityId,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [selectedCityId, createCarrierData.city_id]);
|
}, [
|
||||||
|
selectedCityId,
|
||||||
|
createCarrierData,
|
||||||
|
createCarrierData.city_id,
|
||||||
|
language,
|
||||||
|
setCreateCarrierData,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleCreate = async () => {
|
const handleCreate = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -151,7 +166,7 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
|
|
||||||
toast.success("Перевозчик успешно создан");
|
toast.success("Перевозчик успешно создан");
|
||||||
navigate("/carrier");
|
navigate("/carrier");
|
||||||
} catch (error) {
|
} catch {
|
||||||
toast.error("Ошибка при создании перевозчика");
|
toast.error("Ошибка при создании перевозчика");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -164,27 +179,22 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
media_name?: string;
|
media_name?: string;
|
||||||
media_type: number;
|
media_type: number;
|
||||||
}) => {
|
}) => {
|
||||||
setSelectedMediaId(media.id);
|
setCreateCarrierMedia(activeMediaField, media.id);
|
||||||
setCreateCarrierData(
|
|
||||||
createCarrierData[language].full_name,
|
|
||||||
createCarrierData[language].short_name,
|
|
||||||
createCarrierData.city_id,
|
|
||||||
createCarrierData[language].slogan,
|
|
||||||
media.id,
|
|
||||||
language,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedMedia =
|
const effectivePreviewMediaUrl = isMediaIdEmpty(
|
||||||
selectedMediaId && !isMediaIdEmpty(selectedMediaId)
|
createCarrierData.preview_media,
|
||||||
? mediaStore.media.find((m) => m.id === selectedMediaId)
|
)
|
||||||
: null;
|
|
||||||
const effectiveLogoUrl = isMediaIdEmpty(selectedMediaId)
|
|
||||||
? null
|
? null
|
||||||
: selectedMedia?.id ?? selectedMediaId ?? null;
|
: createCarrierData.preview_media;
|
||||||
|
const effectiveVideoPreviewId = isMediaIdEmpty(
|
||||||
|
createCarrierData.video_preview,
|
||||||
|
)
|
||||||
|
? null
|
||||||
|
: createCarrierData.video_preview;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
<div className="w-full h-full p-3 flex flex-col gap-10">
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<button
|
||||||
@@ -212,8 +222,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
e.target.value as number,
|
e.target.value as number,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -236,8 +244,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
e.target.value,
|
e.target.value,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
createCarrierData.city_id,
|
createCarrierData.city_id,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -253,24 +259,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
e.target.value,
|
e.target.value,
|
||||||
createCarrierData.city_id,
|
createCarrierData.city_id,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Слоган"
|
|
||||||
value={createCarrierData[language].slogan}
|
|
||||||
onChange={(e) =>
|
|
||||||
setCreateCarrierData(
|
|
||||||
createCarrierData[language].full_name,
|
|
||||||
createCarrierData[language].short_name,
|
|
||||||
createCarrierData.city_id,
|
|
||||||
e.target.value,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -286,8 +274,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
createCarrierData.city_id,
|
createCarrierData.city_id,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(createCarrierData), main_color: val }
|
{ ...colorFields(createCarrierData), main_color: val }
|
||||||
)
|
)
|
||||||
@@ -306,8 +292,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
createCarrierData.city_id,
|
createCarrierData.city_id,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(createCarrierData), left_color: val }
|
{ ...colorFields(createCarrierData), left_color: val }
|
||||||
)
|
)
|
||||||
@@ -326,8 +310,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
createCarrierData[language].full_name,
|
createCarrierData[language].full_name,
|
||||||
createCarrierData[language].short_name,
|
createCarrierData[language].short_name,
|
||||||
createCarrierData.city_id,
|
createCarrierData.city_id,
|
||||||
createCarrierData[language].slogan,
|
|
||||||
selectedMediaId || "",
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(createCarrierData), right_color: val }
|
{ ...colorFields(createCarrierData), right_color: val }
|
||||||
)
|
)
|
||||||
@@ -339,36 +321,57 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex flex-col gap-4 max-w-[300px] mx-auto">
|
<div className="w-full flex justify-center items-start gap-10 flex-wrap">
|
||||||
<ImageUploadCard
|
<div className="w-full max-w-[300px]">
|
||||||
title="Логотип перевозчика"
|
<ImageUploadCard
|
||||||
imageKey="thumbnail"
|
title="Изображение сайд-меню"
|
||||||
imageUrl={effectiveLogoUrl}
|
imageKey="image"
|
||||||
onImageClick={() => {
|
imageUrl={effectivePreviewMediaUrl}
|
||||||
setIsPreviewMediaOpen(true);
|
onImageClick={() => {
|
||||||
setMediaId(effectiveLogoUrl ?? "");
|
setIsPreviewMediaOpen(true);
|
||||||
}}
|
setMediaId(effectivePreviewMediaUrl ?? "");
|
||||||
onDeleteImageClick={() => {
|
}}
|
||||||
setSelectedMediaId(null);
|
onDeleteImageClick={() =>
|
||||||
setActiveMenuType(null);
|
setCreateCarrierMedia("preview_media", "")
|
||||||
setCreateCarrierData(
|
}
|
||||||
createCarrierData[language].full_name,
|
onSelectFileClick={() => {
|
||||||
createCarrierData[language].short_name,
|
setActiveMediaField("preview_media");
|
||||||
createCarrierData.city_id,
|
setActiveMenuType("image");
|
||||||
createCarrierData[language].slogan,
|
setIsSelectMediaOpen(true);
|
||||||
"",
|
}}
|
||||||
language,
|
setUploadMediaOpen={() => {
|
||||||
);
|
setActiveMediaField("preview_media");
|
||||||
}}
|
setActiveMenuType("image");
|
||||||
onSelectFileClick={() => {
|
setIsUploadMediaOpen(true);
|
||||||
setActiveMenuType("image");
|
}}
|
||||||
setIsSelectMediaOpen(true);
|
/>
|
||||||
}}
|
</div>
|
||||||
setUploadMediaOpen={() => {
|
<div className="w-full max-w-[300px]">
|
||||||
setIsUploadMediaOpen(true);
|
<VideoPreviewCard
|
||||||
setActiveMenuType("image");
|
title="Видео загрузки"
|
||||||
}}
|
videoId={effectiveVideoPreviewId}
|
||||||
/>
|
onVideoClick={() => {
|
||||||
|
if (effectiveVideoPreviewId) {
|
||||||
|
setMediaId(effectiveVideoPreviewId);
|
||||||
|
setIsPreviewMediaOpen(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDeleteVideoClick={() =>
|
||||||
|
setCreateCarrierMedia("video_preview", "")
|
||||||
|
}
|
||||||
|
onSelectVideoClick={(file) => {
|
||||||
|
setActiveMediaField("video_preview");
|
||||||
|
setActiveMenuType("video_preview");
|
||||||
|
if (file) {
|
||||||
|
editSightStore.setFileToUpload(file);
|
||||||
|
setIsUploadMediaOpen(true);
|
||||||
|
} else {
|
||||||
|
setIsSelectMediaOpen(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -395,7 +398,7 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
open={isSelectMediaOpen}
|
open={isSelectMediaOpen}
|
||||||
onClose={() => setIsSelectMediaOpen(false)}
|
onClose={() => setIsSelectMediaOpen(false)}
|
||||||
onSelectMedia={handleMediaSelect}
|
onSelectMedia={handleMediaSelect}
|
||||||
mediaType={1}
|
mediaType={activeMediaField === "video_preview" ? 2 : 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UploadMediaDialog
|
<UploadMediaDialog
|
||||||
@@ -412,6 +415,6 @@ export const CarrierCreatePage = observer(() => {
|
|||||||
onClose={() => setIsPreviewMediaOpen(false)}
|
onClose={() => setIsPreviewMediaOpen(false)}
|
||||||
mediaId={mediaId}
|
mediaId={mediaId}
|
||||||
/>
|
/>
|
||||||
</Paper>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Paper,
|
|
||||||
TextField,
|
TextField,
|
||||||
Select,
|
Select,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
@@ -22,9 +21,14 @@ import {
|
|||||||
isMediaIdEmpty,
|
isMediaIdEmpty,
|
||||||
LoadingSpinner,
|
LoadingSpinner,
|
||||||
selectedCityStore,
|
selectedCityStore,
|
||||||
|
editSightStore,
|
||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { ImageUploadCard, LanguageSwitcher, DeleteModal } from "@widgets";
|
import {
|
||||||
|
ImageUploadCard,
|
||||||
|
LanguageSwitcher,
|
||||||
|
VideoPreviewCard,
|
||||||
|
} from "@widgets";
|
||||||
import {
|
import {
|
||||||
SelectMediaDialog,
|
SelectMediaDialog,
|
||||||
PreviewMediaDialog,
|
PreviewMediaDialog,
|
||||||
@@ -88,7 +92,12 @@ const ColorPickerField = ({
|
|||||||
export const CarrierEditPage = observer(() => {
|
export const CarrierEditPage = observer(() => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const { getCarrier, setEditCarrierData, editCarrierData } = carrierStore;
|
const {
|
||||||
|
getCarrier,
|
||||||
|
setEditCarrierData,
|
||||||
|
setEditCarrierMedia,
|
||||||
|
editCarrierData,
|
||||||
|
} = carrierStore;
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
const canReadCities = authStore.canRead("cities");
|
const canReadCities = authStore.canRead("cities");
|
||||||
|
|
||||||
@@ -98,10 +107,17 @@ export const CarrierEditPage = observer(() => {
|
|||||||
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
const [isUploadMediaOpen, setIsUploadMediaOpen] = useState(false);
|
||||||
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
const [isPreviewMediaOpen, setIsPreviewMediaOpen] = useState(false);
|
||||||
const [mediaId, setMediaId] = useState("");
|
const [mediaId, setMediaId] = useState("");
|
||||||
const [isDeleteLogoModalOpen, setIsDeleteLogoModalOpen] = useState(false);
|
|
||||||
const [initialCityName, setInitialCityName] = useState("");
|
const [initialCityName, setInitialCityName] = useState("");
|
||||||
|
const [activeMediaField, setActiveMediaField] = useState<
|
||||||
|
"preview_media" | "video_preview"
|
||||||
|
>("preview_media");
|
||||||
const [activeMenuType, setActiveMenuType] = useState<
|
const [activeMenuType, setActiveMenuType] = useState<
|
||||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
| "thumbnail"
|
||||||
|
| "watermark_lu"
|
||||||
|
| "watermark_rd"
|
||||||
|
| "image"
|
||||||
|
| "video_preview"
|
||||||
|
| null
|
||||||
>(null);
|
>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,8 +153,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
carrierData.ru?.full_name || "",
|
carrierData.ru?.full_name || "",
|
||||||
carrierData.ru?.short_name || "",
|
carrierData.ru?.short_name || "",
|
||||||
carrierData.ru?.city_id || 0,
|
carrierData.ru?.city_id || 0,
|
||||||
carrierData.ru?.slogan || "",
|
|
||||||
carrierData.ru?.logo || "",
|
|
||||||
"ru",
|
"ru",
|
||||||
colors,
|
colors,
|
||||||
);
|
);
|
||||||
@@ -146,18 +160,22 @@ export const CarrierEditPage = observer(() => {
|
|||||||
carrierData.en?.full_name || "",
|
carrierData.en?.full_name || "",
|
||||||
carrierData.en?.short_name || "",
|
carrierData.en?.short_name || "",
|
||||||
carrierData.en?.city_id || 0,
|
carrierData.en?.city_id || 0,
|
||||||
carrierData.en?.slogan || "",
|
|
||||||
carrierData.en?.logo || "",
|
|
||||||
"en",
|
"en",
|
||||||
);
|
);
|
||||||
setEditCarrierData(
|
setEditCarrierData(
|
||||||
carrierData.zh?.full_name || "",
|
carrierData.zh?.full_name || "",
|
||||||
carrierData.zh?.short_name || "",
|
carrierData.zh?.short_name || "",
|
||||||
carrierData.zh?.city_id || 0,
|
carrierData.zh?.city_id || 0,
|
||||||
carrierData.zh?.slogan || "",
|
|
||||||
carrierData.zh?.logo || "",
|
|
||||||
"zh",
|
"zh",
|
||||||
);
|
);
|
||||||
|
setEditCarrierMedia(
|
||||||
|
"video_preview",
|
||||||
|
carrierData.ru?.video_preview || "",
|
||||||
|
);
|
||||||
|
setEditCarrierMedia(
|
||||||
|
"preview_media",
|
||||||
|
carrierData.ru?.preview_media || "",
|
||||||
|
);
|
||||||
setInitialCityName(carrierData.ru?.city || "");
|
setInitialCityName(carrierData.ru?.city || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +186,7 @@ export const CarrierEditPage = observer(() => {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
languageStore.setLanguage("ru");
|
languageStore.setLanguage("ru");
|
||||||
}, [id]);
|
}, [id, getCarrier, setEditCarrierData, setEditCarrierMedia]);
|
||||||
|
|
||||||
const handleEdit = async () => {
|
const handleEdit = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -176,7 +194,7 @@ export const CarrierEditPage = observer(() => {
|
|||||||
await carrierStore.editCarrier(Number(id));
|
await carrierStore.editCarrier(Number(id));
|
||||||
toast.success("Перевозчик успешно обновлен");
|
toast.success("Перевозчик успешно обновлен");
|
||||||
navigate("/carrier");
|
navigate("/carrier");
|
||||||
} catch (error) {
|
} catch {
|
||||||
toast.error("Ошибка при обновлении перевозчика");
|
toast.error("Ошибка при обновлении перевозчика");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -189,23 +207,19 @@ export const CarrierEditPage = observer(() => {
|
|||||||
media_name?: string;
|
media_name?: string;
|
||||||
media_type: number;
|
media_type: number;
|
||||||
}) => {
|
}) => {
|
||||||
setEditCarrierData(
|
setEditCarrierMedia(activeMediaField, media.id);
|
||||||
editCarrierData[language].full_name,
|
|
||||||
editCarrierData[language].short_name,
|
|
||||||
editCarrierData.city_id,
|
|
||||||
editCarrierData[language].slogan,
|
|
||||||
media.id,
|
|
||||||
language,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedMedia =
|
const effectivePreviewMediaUrl = isMediaIdEmpty(
|
||||||
editCarrierData.logo && !isMediaIdEmpty(editCarrierData.logo)
|
editCarrierData.preview_media,
|
||||||
? mediaStore.media.find((m) => m.id === editCarrierData.logo)
|
)
|
||||||
: null;
|
|
||||||
const effectiveLogoUrl = isMediaIdEmpty(editCarrierData.logo)
|
|
||||||
? null
|
? null
|
||||||
: (selectedMedia?.id ?? editCarrierData.logo);
|
: editCarrierData.preview_media;
|
||||||
|
const effectiveVideoPreviewId = isMediaIdEmpty(
|
||||||
|
editCarrierData.video_preview,
|
||||||
|
)
|
||||||
|
? null
|
||||||
|
: editCarrierData.video_preview;
|
||||||
|
|
||||||
const baseCities = canReadCities
|
const baseCities = canReadCities
|
||||||
? cityStore.cities["ru"].data
|
? cityStore.cities["ru"].data
|
||||||
@@ -248,7 +262,7 @@ export const CarrierEditPage = observer(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
<div className="w-full h-full p-3 flex flex-col gap-10">
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<button
|
||||||
@@ -275,8 +289,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
editCarrierData[language].full_name,
|
editCarrierData[language].full_name,
|
||||||
editCarrierData[language].short_name,
|
editCarrierData[language].short_name,
|
||||||
Number(e.target.value),
|
Number(e.target.value),
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -299,8 +311,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
e.target.value,
|
e.target.value,
|
||||||
editCarrierData[language].short_name,
|
editCarrierData[language].short_name,
|
||||||
editCarrierData.city_id,
|
editCarrierData.city_id,
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -316,24 +326,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
editCarrierData[language].full_name,
|
editCarrierData[language].full_name,
|
||||||
e.target.value,
|
e.target.value,
|
||||||
editCarrierData.city_id,
|
editCarrierData.city_id,
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="Слоган"
|
|
||||||
value={editCarrierData[language].slogan}
|
|
||||||
onChange={(e) =>
|
|
||||||
setEditCarrierData(
|
|
||||||
editCarrierData[language].full_name,
|
|
||||||
editCarrierData[language].short_name,
|
|
||||||
editCarrierData.city_id,
|
|
||||||
e.target.value,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -349,8 +341,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
editCarrierData[language].full_name,
|
editCarrierData[language].full_name,
|
||||||
editCarrierData[language].short_name,
|
editCarrierData[language].short_name,
|
||||||
editCarrierData.city_id,
|
editCarrierData.city_id,
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(editCarrierData), main_color: val },
|
{ ...colorFields(editCarrierData), main_color: val },
|
||||||
)
|
)
|
||||||
@@ -370,8 +360,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
editCarrierData[language].full_name,
|
editCarrierData[language].full_name,
|
||||||
editCarrierData[language].short_name,
|
editCarrierData[language].short_name,
|
||||||
editCarrierData.city_id,
|
editCarrierData.city_id,
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(editCarrierData), left_color: val },
|
{ ...colorFields(editCarrierData), left_color: val },
|
||||||
)
|
)
|
||||||
@@ -391,8 +379,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
editCarrierData[language].full_name,
|
editCarrierData[language].full_name,
|
||||||
editCarrierData[language].short_name,
|
editCarrierData[language].short_name,
|
||||||
editCarrierData.city_id,
|
editCarrierData.city_id,
|
||||||
editCarrierData[language].slogan,
|
|
||||||
editCarrierData.logo,
|
|
||||||
language,
|
language,
|
||||||
{ ...colorFields(editCarrierData), right_color: val },
|
{ ...colorFields(editCarrierData), right_color: val },
|
||||||
)
|
)
|
||||||
@@ -405,27 +391,57 @@ export const CarrierEditPage = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex flex-col gap-4 max-w-[300px] mx-auto">
|
<div className="w-full flex justify-center items-start gap-10 flex-wrap">
|
||||||
<ImageUploadCard
|
<div className="w-full max-w-[300px]">
|
||||||
title="Логотип перевозчика"
|
<ImageUploadCard
|
||||||
imageKey="thumbnail"
|
title="Изображение сайд-меню"
|
||||||
imageUrl={effectiveLogoUrl}
|
imageKey="image"
|
||||||
onImageClick={() => {
|
imageUrl={effectivePreviewMediaUrl}
|
||||||
setIsPreviewMediaOpen(true);
|
onImageClick={() => {
|
||||||
setMediaId(effectiveLogoUrl ?? "");
|
setIsPreviewMediaOpen(true);
|
||||||
}}
|
setMediaId(effectivePreviewMediaUrl ?? "");
|
||||||
onDeleteImageClick={() => {
|
}}
|
||||||
setIsDeleteLogoModalOpen(true);
|
onDeleteImageClick={() =>
|
||||||
}}
|
setEditCarrierMedia("preview_media", "")
|
||||||
onSelectFileClick={() => {
|
}
|
||||||
setActiveMenuType("image");
|
onSelectFileClick={() => {
|
||||||
setIsSelectMediaOpen(true);
|
setActiveMediaField("preview_media");
|
||||||
}}
|
setActiveMenuType("image");
|
||||||
setUploadMediaOpen={() => {
|
setIsSelectMediaOpen(true);
|
||||||
setIsUploadMediaOpen(true);
|
}}
|
||||||
setActiveMenuType("image");
|
setUploadMediaOpen={() => {
|
||||||
}}
|
setActiveMediaField("preview_media");
|
||||||
/>
|
setActiveMenuType("image");
|
||||||
|
setIsUploadMediaOpen(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-full max-w-[300px]">
|
||||||
|
<VideoPreviewCard
|
||||||
|
title="Видео загрузки"
|
||||||
|
videoId={effectiveVideoPreviewId}
|
||||||
|
onVideoClick={() => {
|
||||||
|
if (effectiveVideoPreviewId) {
|
||||||
|
setMediaId(effectiveVideoPreviewId);
|
||||||
|
setIsPreviewMediaOpen(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDeleteVideoClick={() =>
|
||||||
|
setEditCarrierMedia("video_preview", "")
|
||||||
|
}
|
||||||
|
onSelectVideoClick={(file) => {
|
||||||
|
setActiveMediaField("video_preview");
|
||||||
|
setActiveMenuType("video_preview");
|
||||||
|
if (file) {
|
||||||
|
editSightStore.setFileToUpload(file);
|
||||||
|
setIsUploadMediaOpen(true);
|
||||||
|
} else {
|
||||||
|
setIsSelectMediaOpen(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -451,7 +467,7 @@ export const CarrierEditPage = observer(() => {
|
|||||||
open={isSelectMediaOpen}
|
open={isSelectMediaOpen}
|
||||||
onClose={() => setIsSelectMediaOpen(false)}
|
onClose={() => setIsSelectMediaOpen(false)}
|
||||||
onSelectMedia={handleMediaSelect}
|
onSelectMedia={handleMediaSelect}
|
||||||
mediaType={1}
|
mediaType={activeMediaField === "video_preview" ? 2 : 1}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UploadMediaDialog
|
<UploadMediaDialog
|
||||||
@@ -469,22 +485,6 @@ export const CarrierEditPage = observer(() => {
|
|||||||
mediaId={mediaId}
|
mediaId={mediaId}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DeleteModal
|
</div>
|
||||||
open={isDeleteLogoModalOpen}
|
|
||||||
onDelete={() => {
|
|
||||||
setEditCarrierData(
|
|
||||||
editCarrierData[language].full_name,
|
|
||||||
editCarrierData[language].short_name,
|
|
||||||
editCarrierData.city_id,
|
|
||||||
editCarrierData[language].slogan,
|
|
||||||
"",
|
|
||||||
language,
|
|
||||||
);
|
|
||||||
setIsDeleteLogoModalOpen(false);
|
|
||||||
}}
|
|
||||||
onCancel={() => setIsDeleteLogoModalOpen(false)}
|
|
||||||
edit
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,16 +7,8 @@ import {
|
|||||||
InputLabel,
|
InputLabel,
|
||||||
Typography,
|
Typography,
|
||||||
Box,
|
Box,
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import { ImageUploadCard } from "@widgets";
|
||||||
MediaViewer,
|
|
||||||
VideoPreviewCard,
|
|
||||||
ImageUploadCard,
|
|
||||||
} from "@widgets";
|
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { ArrowLeft, Loader2, Save, Plus, X } from "lucide-react";
|
import { ArrowLeft, Loader2, Save, Plus, X } from "lucide-react";
|
||||||
import { useEffect, useState, useMemo } from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
@@ -59,14 +51,10 @@ export const RouteCreatePage = observer(() => {
|
|||||||
const [centerLat, setCenterLat] = useState("");
|
const [centerLat, setCenterLat] = useState("");
|
||||||
const [centerLng, setCenterLng] = useState("");
|
const [centerLng, setCenterLng] = useState("");
|
||||||
const [videoTimer, setVideoTimer] = useState(420);
|
const [videoTimer, setVideoTimer] = useState(420);
|
||||||
const [videoPreview, setVideoPreview] = useState<string>("");
|
|
||||||
const [icon, setIcon] = useState<string>("");
|
const [icon, setIcon] = useState<string>("");
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
|
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false);
|
|
||||||
const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false);
|
|
||||||
const [isUploadVideoDialogOpen, setIsUploadVideoDialogOpen] = useState(false);
|
|
||||||
const [isSelectIconDialogOpen, setIsSelectIconDialogOpen] = useState(false);
|
const [isSelectIconDialogOpen, setIsSelectIconDialogOpen] = useState(false);
|
||||||
const [isUploadIconDialogOpen, setIsUploadIconDialogOpen] = useState(false);
|
const [isUploadIconDialogOpen, setIsUploadIconDialogOpen] = useState(false);
|
||||||
const [isPreviewIconOpen, setIsPreviewIconOpen] = useState(false);
|
const [isPreviewIconOpen, setIsPreviewIconOpen] = useState(false);
|
||||||
@@ -74,7 +62,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
const [activeIconMenuType, setActiveIconMenuType] = useState<
|
const [activeIconMenuType, setActiveIconMenuType] = useState<
|
||||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
||||||
>(null);
|
>(null);
|
||||||
const [fileToUpload, setFileToUpload] = useState<File | null>(null);
|
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -140,40 +127,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
articlesStore.getArticleList();
|
articlesStore.getArticleList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleVideoSelect = (media: {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
media_name?: string;
|
|
||||||
media_type: number;
|
|
||||||
}) => {
|
|
||||||
setVideoPreview(media.id);
|
|
||||||
setIsSelectVideoDialogOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoFileSelect = (file?: File) => {
|
|
||||||
if (file) {
|
|
||||||
setFileToUpload(file);
|
|
||||||
setIsUploadVideoDialogOpen(true);
|
|
||||||
} else {
|
|
||||||
setIsSelectVideoDialogOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoUpload = (media: {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
media_name?: string;
|
|
||||||
media_type: number;
|
|
||||||
}) => {
|
|
||||||
setVideoPreview(media.id);
|
|
||||||
setIsUploadVideoDialogOpen(false);
|
|
||||||
setFileToUpload(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoPreviewClick = () => {
|
|
||||||
setIsVideoPreviewOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleIconSelect = (media: {
|
const handleIconSelect = (media: {
|
||||||
id: string;
|
id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
@@ -189,7 +142,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
? mediaStore.media.find((m) => m.id === icon)
|
? mediaStore.media.find((m) => m.id === icon)
|
||||||
: null;
|
: null;
|
||||||
const effectiveIconUrl = isMediaIdEmpty(icon) ? null : selectedIconMedia?.id ?? icon;
|
const effectiveIconUrl = isMediaIdEmpty(icon) ? null : selectedIconMedia?.id ?? icon;
|
||||||
const effectiveVideoId = isMediaIdEmpty(videoPreview) ? null : videoPreview;
|
|
||||||
|
|
||||||
const handleCreateRoute = async () => {
|
const handleCreateRoute = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -284,7 +236,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
center_latitude,
|
center_latitude,
|
||||||
center_longitude,
|
center_longitude,
|
||||||
path,
|
path,
|
||||||
video_preview: !isMediaIdEmpty(videoPreview) ? videoPreview : undefined,
|
|
||||||
icon: !isMediaIdEmpty(icon) ? icon : undefined,
|
icon: !isMediaIdEmpty(icon) ? icon : undefined,
|
||||||
video_timer: videoTimer,
|
video_timer: videoTimer,
|
||||||
};
|
};
|
||||||
@@ -485,16 +436,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4 max-w-[300px]">
|
|
||||||
<VideoPreviewCard
|
|
||||||
title="Видеозаставка"
|
|
||||||
videoId={effectiveVideoId}
|
|
||||||
onVideoClick={handleVideoPreviewClick}
|
|
||||||
onDeleteVideoClick={() => setVideoPreview("")}
|
|
||||||
onSelectVideoClick={handleVideoFileSelect}
|
|
||||||
className="w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<FormControl fullWidth required>
|
<FormControl fullWidth required>
|
||||||
@@ -578,7 +519,7 @@ export const RouteCreatePage = observer(() => {
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
className="w-full"
|
className="w-full"
|
||||||
label="Таймер видео заставки (сек)"
|
label="Таймер показа видео при бездействии (сек)"
|
||||||
type="number"
|
type="number"
|
||||||
value={videoTimer}
|
value={videoTimer}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -611,51 +552,6 @@ export const RouteCreatePage = observer(() => {
|
|||||||
onClose={() => setIsSelectArticleDialogOpen(false)}
|
onClose={() => setIsSelectArticleDialogOpen(false)}
|
||||||
onSelectArticle={handleArticleSelect}
|
onSelectArticle={handleArticleSelect}
|
||||||
/>
|
/>
|
||||||
<SelectMediaDialog
|
|
||||||
open={isSelectVideoDialogOpen}
|
|
||||||
onClose={() => setIsSelectVideoDialogOpen(false)}
|
|
||||||
onSelectMedia={handleVideoSelect}
|
|
||||||
mediaType={2}
|
|
||||||
/>
|
|
||||||
{effectiveVideoId && (
|
|
||||||
<Dialog
|
|
||||||
open={isVideoPreviewOpen}
|
|
||||||
onClose={() => setIsVideoPreviewOpen(false)}
|
|
||||||
maxWidth="md"
|
|
||||||
fullWidth
|
|
||||||
>
|
|
||||||
<DialogTitle>Предпросмотр видео</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<Box className="flex justify-center items-center p-4">
|
|
||||||
<MediaViewer
|
|
||||||
media={{
|
|
||||||
id: effectiveVideoId,
|
|
||||||
media_type: 2,
|
|
||||||
filename: "video_preview",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => setIsVideoPreviewOpen(false)}>
|
|
||||||
Закрыть
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
)}
|
|
||||||
<UploadMediaDialog
|
|
||||||
open={isUploadVideoDialogOpen}
|
|
||||||
onClose={() => {
|
|
||||||
setIsUploadVideoDialogOpen(false);
|
|
||||||
setFileToUpload(null);
|
|
||||||
}}
|
|
||||||
hardcodeType="video_preview"
|
|
||||||
contextObjectName={routeName || "Маршрут"}
|
|
||||||
contextType="sight"
|
|
||||||
initialFile={fileToUpload || undefined}
|
|
||||||
afterUpload={handleVideoUpload}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SelectMediaDialog
|
<SelectMediaDialog
|
||||||
open={isSelectIconDialogOpen}
|
open={isSelectIconDialogOpen}
|
||||||
onClose={() => setIsSelectIconDialogOpen(false)}
|
onClose={() => setIsSelectIconDialogOpen(false)}
|
||||||
|
|||||||
@@ -7,14 +7,8 @@ import {
|
|||||||
InputLabel,
|
InputLabel,
|
||||||
Typography,
|
Typography,
|
||||||
Box,
|
Box,
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import {
|
||||||
MediaViewer,
|
|
||||||
VideoPreviewCard,
|
|
||||||
ImageUploadCard,
|
ImageUploadCard,
|
||||||
DeleteModal,
|
DeleteModal,
|
||||||
} from "@widgets";
|
} from "@widgets";
|
||||||
@@ -54,9 +48,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
const [isLoadingData, setIsLoadingData] = useState(true);
|
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||||
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
|
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false);
|
|
||||||
const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false);
|
|
||||||
const [isUploadVideoDialogOpen, setIsUploadVideoDialogOpen] = useState(false);
|
|
||||||
const [isSelectIconDialogOpen, setIsSelectIconDialogOpen] = useState(false);
|
const [isSelectIconDialogOpen, setIsSelectIconDialogOpen] = useState(false);
|
||||||
const [isUploadIconDialogOpen, setIsUploadIconDialogOpen] = useState(false);
|
const [isUploadIconDialogOpen, setIsUploadIconDialogOpen] = useState(false);
|
||||||
const [isPreviewIconOpen, setIsPreviewIconOpen] = useState(false);
|
const [isPreviewIconOpen, setIsPreviewIconOpen] = useState(false);
|
||||||
@@ -65,7 +56,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
const [activeIconMenuType, setActiveIconMenuType] = useState<
|
const [activeIconMenuType, setActiveIconMenuType] = useState<
|
||||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
"thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null
|
||||||
>(null);
|
>(null);
|
||||||
const [fileToUpload, setFileToUpload] = useState<File | null>(null);
|
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
const [coordinates, setCoordinates] = useState<string>("");
|
const [coordinates, setCoordinates] = useState<string>("");
|
||||||
|
|
||||||
@@ -114,9 +104,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
const effectiveIconUrl = isMediaIdEmpty(editRouteData.icon)
|
const effectiveIconUrl = isMediaIdEmpty(editRouteData.icon)
|
||||||
? null
|
? null
|
||||||
: (selectedIconMedia?.id ?? editRouteData.icon);
|
: (selectedIconMedia?.id ?? editRouteData.icon);
|
||||||
const effectiveVideoId = isMediaIdEmpty(editRouteData.video_preview)
|
|
||||||
? null
|
|
||||||
: editRouteData.video_preview;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editRouteData.path && editRouteData.path.length > 0) {
|
if (editRouteData.path && editRouteData.path.length > 0) {
|
||||||
@@ -238,46 +225,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
articlesStore.getArticleList();
|
articlesStore.getArticleList();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleVideoSelect = (media: {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
media_name?: string;
|
|
||||||
media_type: number;
|
|
||||||
}) => {
|
|
||||||
routeStore.setEditRouteData({
|
|
||||||
video_preview: media.id,
|
|
||||||
});
|
|
||||||
setIsSelectVideoDialogOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoFileSelect = (file?: File) => {
|
|
||||||
if (file) {
|
|
||||||
setFileToUpload(file);
|
|
||||||
setIsUploadVideoDialogOpen(true);
|
|
||||||
} else {
|
|
||||||
setIsSelectVideoDialogOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoUpload = (media: {
|
|
||||||
id: string;
|
|
||||||
filename: string;
|
|
||||||
media_name?: string;
|
|
||||||
media_type: number;
|
|
||||||
}) => {
|
|
||||||
routeStore.setEditRouteData({
|
|
||||||
video_preview: media.id,
|
|
||||||
});
|
|
||||||
setIsUploadVideoDialogOpen(false);
|
|
||||||
setFileToUpload(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVideoPreviewClick = () => {
|
|
||||||
if (editRouteData.video_preview && editRouteData.video_preview !== "") {
|
|
||||||
setIsVideoPreviewOpen(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Получаем название выбранной статьи для отображения
|
// Получаем название выбранной статьи для отображения
|
||||||
const selectedArticle = articlesStore.articleList.ru.data.find(
|
const selectedArticle = articlesStore.articleList.ru.data.find(
|
||||||
(article) => article.id === editRouteData.governor_appeal
|
(article) => article.id === editRouteData.governor_appeal
|
||||||
@@ -555,7 +502,7 @@ export const RouteEditPage = observer(() => {
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
className="w-full"
|
className="w-full"
|
||||||
label="Таймер видео заставки (сек)"
|
label="Таймер показа видео при бездействии (сек)"
|
||||||
type="number"
|
type="number"
|
||||||
value={editRouteData.video_timer ?? 420}
|
value={editRouteData.video_timer ?? 420}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -646,18 +593,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4 max-w-[300px]">
|
|
||||||
<VideoPreviewCard
|
|
||||||
title="Видеозаставка"
|
|
||||||
videoId={effectiveVideoId}
|
|
||||||
onVideoClick={handleVideoPreviewClick}
|
|
||||||
onDeleteVideoClick={() => {
|
|
||||||
routeStore.setEditRouteData({ video_preview: "" });
|
|
||||||
}}
|
|
||||||
onSelectVideoClick={handleVideoFileSelect}
|
|
||||||
className="w-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -703,49 +638,6 @@ export const RouteEditPage = observer(() => {
|
|||||||
onClose={() => setIsSelectArticleDialogOpen(false)}
|
onClose={() => setIsSelectArticleDialogOpen(false)}
|
||||||
onSelectArticle={handleArticleSelect}
|
onSelectArticle={handleArticleSelect}
|
||||||
/>
|
/>
|
||||||
<SelectMediaDialog
|
|
||||||
open={isSelectVideoDialogOpen}
|
|
||||||
onClose={() => setIsSelectVideoDialogOpen(false)}
|
|
||||||
onSelectMedia={handleVideoSelect}
|
|
||||||
mediaType={2}
|
|
||||||
/>
|
|
||||||
<Dialog
|
|
||||||
open={isVideoPreviewOpen}
|
|
||||||
onClose={() => setIsVideoPreviewOpen(false)}
|
|
||||||
maxWidth="md"
|
|
||||||
fullWidth
|
|
||||||
>
|
|
||||||
<DialogTitle>Предпросмотр видео</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<Box className="flex justify-center items-center p-4">
|
|
||||||
{effectiveVideoId && (
|
|
||||||
<MediaViewer
|
|
||||||
media={{
|
|
||||||
id: effectiveVideoId,
|
|
||||||
media_type: 2,
|
|
||||||
filename: "video_preview",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => setIsVideoPreviewOpen(false)}>Закрыть</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
<UploadMediaDialog
|
|
||||||
open={isUploadVideoDialogOpen}
|
|
||||||
onClose={() => {
|
|
||||||
setIsUploadVideoDialogOpen(false);
|
|
||||||
setFileToUpload(null);
|
|
||||||
}}
|
|
||||||
hardcodeType="video_preview"
|
|
||||||
contextObjectName={editRouteData.route_name || "Маршрут"}
|
|
||||||
contextType="sight"
|
|
||||||
initialFile={fileToUpload || undefined}
|
|
||||||
afterUpload={handleVideoUpload}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SelectMediaDialog
|
<SelectMediaDialog
|
||||||
open={isSelectIconDialogOpen}
|
open={isSelectIconDialogOpen}
|
||||||
onClose={() => setIsSelectIconDialogOpen(false)}
|
onClose={() => setIsSelectIconDialogOpen(false)}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
import { useNavigate, useNavigationType } from "react-router";
|
import { useNavigate, useNavigationType } from "react-router";
|
||||||
import { MediaViewer } from "@widgets";
|
|
||||||
import { useMapData } from "./MapDataContext";
|
import { useMapData } from "./MapDataContext";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { authInstance, isMediaIdEmpty } from "@shared";
|
import { authInstance } from "@shared";
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
import LanguageSelector from "./web-gl/LanguageSelector";
|
import LanguageSelector from "./web-gl/LanguageSelector";
|
||||||
|
|
||||||
@@ -17,9 +16,8 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const navigationType = useNavigationType();
|
const navigationType = useNavigationType();
|
||||||
const { routeData } = useMapData();
|
const { routeData } = useMapData();
|
||||||
const [carrierLogo, setCarrierLogo] = useState<string | null>(null);
|
const [previewMedia, setPreviewMedia] = useState<string | null>(null);
|
||||||
const [carrierSlogan, setCarrierSlogan] = useState<string | null>(null);
|
const [isPreviewMediaError, setIsPreviewMediaError] = useState(false);
|
||||||
const [carrierShortName, setCarrierShortName] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchCarrierData() {
|
async function fetchCarrierData() {
|
||||||
@@ -27,9 +25,8 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
const carrier = (
|
const carrier = (
|
||||||
await authInstance.get(`/carrier/${routeData.carrier_id}`)
|
await authInstance.get(`/carrier/${routeData.carrier_id}`)
|
||||||
).data;
|
).data;
|
||||||
setCarrierLogo(carrier.logo);
|
setPreviewMedia(carrier.preview_media ?? null);
|
||||||
setCarrierSlogan(carrier.slogan ?? null);
|
setIsPreviewMediaError(false);
|
||||||
setCarrierShortName(carrier.short_name ?? null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchCarrierData();
|
fetchCarrierData();
|
||||||
@@ -94,43 +91,6 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
pointerEvents: open ? "auto" : "none",
|
pointerEvents: open ? "auto" : "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Герб — .side-menu-crest */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: 170,
|
|
||||||
height: 170,
|
|
||||||
alignSelf: "flex-start",
|
|
||||||
marginLeft: 20,
|
|
||||||
backgroundColor: "rgba(255,255,255,0.15)",
|
|
||||||
borderRadius: 8,
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
color: "rgba(255,255,255,0.5)",
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 500,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Герб
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Слоган — .side-menu-label */}
|
|
||||||
{carrierSlogan && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginTop: 10,
|
|
||||||
textAlign: "left",
|
|
||||||
fontSize: 15,
|
|
||||||
padding: "0 20px",
|
|
||||||
alignSelf: "flex-start",
|
|
||||||
fontWeight: 400,
|
|
||||||
lineHeight: "150%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{carrierSlogan}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Кнопки — .side-menu-buttons */}
|
{/* Кнопки — .side-menu-buttons */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -175,39 +135,14 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* .side-menu-carrier-block */}
|
|
||||||
<div style={{ padding: "0 20px" }}>
|
|
||||||
{carrierLogo && !isMediaIdEmpty(carrierLogo) && (
|
|
||||||
<div style={{ width: 170 }}>
|
|
||||||
<MediaViewer
|
|
||||||
media={{
|
|
||||||
id: carrierLogo,
|
|
||||||
media_type: 1,
|
|
||||||
filename: "carrier_logo",
|
|
||||||
}}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{carrierShortName && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
marginTop: 4,
|
|
||||||
textAlign: "left",
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 700,
|
|
||||||
lineHeight: "150%",
|
|
||||||
color: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{carrierShortName}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* .side-menu-bottom-photo */}
|
{/* .side-menu-bottom-photo */}
|
||||||
<img
|
<img
|
||||||
src="/side-menu-photo.png"
|
src={
|
||||||
|
previewMedia && !isPreviewMediaError
|
||||||
|
? `${import.meta.env.VITE_KRBL_MEDIA}${previewMedia}/download?token=${localStorage.getItem("token") ?? ""}`
|
||||||
|
: "/side-menu-photo.png"
|
||||||
|
}
|
||||||
|
onError={() => setIsPreviewMediaError(true)}
|
||||||
alt=""
|
alt=""
|
||||||
style={{
|
style={{
|
||||||
width: "288px",
|
width: "288px",
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export const SnapshotListPage = observer(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "created_at",
|
field: "created_at",
|
||||||
headerName: "Дата создания",
|
headerName: "Дата создания (UTC+03:00, MSK)",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
renderCell: (params: GridRenderCellParams) => {
|
renderCell: (params: GridRenderCellParams) => {
|
||||||
return <div>{params.value ? params.value : "-"}</div>;
|
return <div>{params.value ? params.value : "-"}</div>;
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { mediaStore, MEDIA_TYPE_LABELS } from "@shared";
|
import {
|
||||||
|
mediaStore,
|
||||||
|
MEDIA_TYPE_LABELS,
|
||||||
|
PreviewBackgroundToggle,
|
||||||
|
} from "@shared";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
@@ -29,6 +33,8 @@ export const PreviewMediaDialog = observer(
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [success, setSuccess] = useState(false);
|
const [success, setSuccess] = useState(false);
|
||||||
|
const [isPreviewBackgroundDark, setIsPreviewBackgroundDark] =
|
||||||
|
useState(false);
|
||||||
const media = mediaId
|
const media = mediaId
|
||||||
? mediaStore.media.find((m) => m.id === mediaId)
|
? mediaStore.media.find((m) => m.id === mediaId)
|
||||||
: null;
|
: null;
|
||||||
@@ -40,6 +46,7 @@ export const PreviewMediaDialog = observer(
|
|||||||
if (media) {
|
if (media) {
|
||||||
setMediaName(media.media_name);
|
setMediaName(media.media_name);
|
||||||
setMediaFilename(media.filename);
|
setMediaFilename(media.filename);
|
||||||
|
setIsPreviewBackgroundDark(false);
|
||||||
}
|
}
|
||||||
}, [media]);
|
}, [media]);
|
||||||
|
|
||||||
@@ -141,8 +148,19 @@ export const PreviewMediaDialog = observer(
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
|
position: "relative",
|
||||||
|
backgroundColor: isPreviewBackgroundDark ? "#000" : "#fff",
|
||||||
|
transition: "background-color 150ms ease",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{[1, 3, 4, 5].includes(media.media_type) && (
|
||||||
|
<PreviewBackgroundToggle
|
||||||
|
dark={isPreviewBackgroundDark}
|
||||||
|
onToggle={() =>
|
||||||
|
setIsPreviewBackgroundDark((value) => !value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<MediaViewer
|
<MediaViewer
|
||||||
media={{
|
media={{
|
||||||
id: mediaId,
|
id: mediaId,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
clearBlobAndGLTFCache,
|
clearBlobAndGLTFCache,
|
||||||
authStore,
|
authStore,
|
||||||
snapshotStore,
|
snapshotStore,
|
||||||
|
PreviewBackgroundToggle,
|
||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useEffect, useState, useRef } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
@@ -90,6 +91,8 @@ export const UploadMediaDialog = observer(
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const [isPreviewLoaded, setIsPreviewLoaded] = useState(false);
|
const [isPreviewLoaded, setIsPreviewLoaded] = useState(false);
|
||||||
|
const [isPreviewBackgroundDark, setIsPreviewBackgroundDark] =
|
||||||
|
useState(false);
|
||||||
const previousMediaUrlRef = useRef<string | null>(null);
|
const previousMediaUrlRef = useRef<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -347,6 +350,7 @@ export const UploadMediaDialog = observer(
|
|||||||
setMediaUrl(null);
|
setMediaUrl(null);
|
||||||
setMediaFile(null);
|
setMediaFile(null);
|
||||||
setIsPreviewLoaded(false);
|
setIsPreviewLoaded(false);
|
||||||
|
setIsPreviewBackgroundDark(false);
|
||||||
previousMediaUrlRef.current = null;
|
previousMediaUrlRef.current = null;
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
@@ -416,8 +420,18 @@ export const UploadMediaDialog = observer(
|
|||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
backgroundColor: isPreviewBackgroundDark ? "#000" : "#fff",
|
||||||
|
transition: "background-color 150ms ease",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{mediaUrl && mediaType !== 2 && mediaType !== 6 && (
|
||||||
|
<PreviewBackgroundToggle
|
||||||
|
dark={isPreviewBackgroundDark}
|
||||||
|
onToggle={() =>
|
||||||
|
setIsPreviewBackgroundDark((value) => !value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{!isPreviewLoaded && mediaUrl && (
|
{!isPreviewLoaded && mediaUrl && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ export type Carrier = {
|
|||||||
id: number;
|
id: number;
|
||||||
short_name: string;
|
short_name: string;
|
||||||
full_name: string;
|
full_name: string;
|
||||||
slogan: string;
|
|
||||||
city: string;
|
city: string;
|
||||||
city_id: number;
|
city_id: number;
|
||||||
logo: string;
|
preview_media?: string;
|
||||||
|
video_preview?: string;
|
||||||
main_color: string;
|
main_color: string;
|
||||||
left_color: string;
|
left_color: string;
|
||||||
right_color: string;
|
right_color: string;
|
||||||
@@ -111,38 +111,40 @@ class CarrierStore {
|
|||||||
|
|
||||||
createCarrierData = {
|
createCarrierData = {
|
||||||
city_id: 0,
|
city_id: 0,
|
||||||
logo: "",
|
preview_media: "",
|
||||||
|
video_preview: "",
|
||||||
main_color: "",
|
main_color: "",
|
||||||
left_color: "",
|
left_color: "",
|
||||||
right_color: "",
|
right_color: "",
|
||||||
ru: {
|
ru: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setCreateCarrierMedia = (
|
||||||
|
field: "preview_media" | "video_preview",
|
||||||
|
mediaId: string
|
||||||
|
) => {
|
||||||
|
this.createCarrierData[field] = mediaId;
|
||||||
|
};
|
||||||
|
|
||||||
setCreateCarrierData = (
|
setCreateCarrierData = (
|
||||||
fullName: string,
|
fullName: string,
|
||||||
shortName: string,
|
shortName: string,
|
||||||
cityId: number,
|
cityId: number,
|
||||||
slogan: string,
|
|
||||||
logoId: string,
|
|
||||||
language: Language,
|
language: Language,
|
||||||
colors?: { main_color?: string; left_color?: string; right_color?: string }
|
colors?: { main_color?: string; left_color?: string; right_color?: string }
|
||||||
) => {
|
) => {
|
||||||
this.createCarrierData.city_id = cityId;
|
this.createCarrierData.city_id = cityId;
|
||||||
this.createCarrierData.logo = logoId;
|
|
||||||
if (colors) {
|
if (colors) {
|
||||||
if (colors.main_color !== undefined) this.createCarrierData.main_color = colors.main_color;
|
if (colors.main_color !== undefined) this.createCarrierData.main_color = colors.main_color;
|
||||||
if (colors.left_color !== undefined) this.createCarrierData.left_color = colors.left_color;
|
if (colors.left_color !== undefined) this.createCarrierData.left_color = colors.left_color;
|
||||||
@@ -151,7 +153,6 @@ class CarrierStore {
|
|||||||
this.createCarrierData[language] = {
|
this.createCarrierData[language] = {
|
||||||
full_name: fullName,
|
full_name: fullName,
|
||||||
short_name: shortName,
|
short_name: shortName,
|
||||||
slogan: slogan,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,8 +207,12 @@ class CarrierStore {
|
|||||||
short_name: (this.createCarrierData[language].short_name || "").trim(),
|
short_name: (this.createCarrierData[language].short_name || "").trim(),
|
||||||
city: cityName,
|
city: cityName,
|
||||||
city_id: this.createCarrierData.city_id,
|
city_id: this.createCarrierData.city_id,
|
||||||
slogan: (this.createCarrierData[language].slogan || "").trim(),
|
...(this.createCarrierData.preview_media
|
||||||
...(this.createCarrierData.logo ? { logo: this.createCarrierData.logo } : {}),
|
? { preview_media: this.createCarrierData.preview_media }
|
||||||
|
: {}),
|
||||||
|
...(this.createCarrierData.video_preview
|
||||||
|
? { video_preview: this.createCarrierData.video_preview }
|
||||||
|
: {}),
|
||||||
...(this.createCarrierData.main_color ? { main_color: this.createCarrierData.main_color } : {}),
|
...(this.createCarrierData.main_color ? { main_color: this.createCarrierData.main_color } : {}),
|
||||||
...(this.createCarrierData.left_color ? { left_color: this.createCarrierData.left_color } : {}),
|
...(this.createCarrierData.left_color ? { left_color: this.createCarrierData.left_color } : {}),
|
||||||
...(this.createCarrierData.right_color ? { right_color: this.createCarrierData.right_color } : {}),
|
...(this.createCarrierData.right_color ? { right_color: this.createCarrierData.right_color } : {}),
|
||||||
@@ -221,55 +226,55 @@ class CarrierStore {
|
|||||||
this.carriers[language].data.push(response.data);
|
this.carriers[language].data.push(response.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const lang of ["ru", "en", "zh"].filter((l) => l !== language)) {
|
for (const lang of (["ru", "en", "zh"] as const).filter(
|
||||||
|
(item) => item !== language
|
||||||
|
)) {
|
||||||
const cityNameForLang = this.resolveCityName(
|
const cityNameForLang = this.resolveCityName(
|
||||||
this.createCarrierData.city_id,
|
this.createCarrierData.city_id,
|
||||||
lang as Language
|
lang
|
||||||
);
|
);
|
||||||
|
const localizedData = this.createCarrierData[lang];
|
||||||
const patchPayload = {
|
const patchPayload = {
|
||||||
// @ts-ignore
|
full_name: (localizedData.full_name || "").trim(),
|
||||||
full_name: ((this.createCarrierData[lang as any].full_name as string) || "").trim(),
|
short_name: (localizedData.short_name || "").trim(),
|
||||||
// @ts-ignore
|
|
||||||
short_name: ((this.createCarrierData[lang as any].short_name as string) || "").trim(),
|
|
||||||
city: cityNameForLang || cityName,
|
city: cityNameForLang || cityName,
|
||||||
city_id: this.createCarrierData.city_id,
|
city_id: this.createCarrierData.city_id,
|
||||||
// @ts-ignore
|
...(this.createCarrierData.preview_media
|
||||||
slogan: ((this.createCarrierData[lang as any].slogan as string) || "").trim(),
|
? { preview_media: this.createCarrierData.preview_media }
|
||||||
...(this.createCarrierData.logo
|
: {}),
|
||||||
? { logo: this.createCarrierData.logo }
|
...(this.createCarrierData.video_preview
|
||||||
|
? { video_preview: this.createCarrierData.video_preview }
|
||||||
: {}),
|
: {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await languageInstance(lang as Language).patch(
|
const response = await languageInstance(lang).patch(
|
||||||
`/carrier/${carrierId}`,
|
`/carrier/${carrierId}`,
|
||||||
patchPayload
|
patchPayload
|
||||||
);
|
);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.carriers[lang as keyof Carriers].data.push(response.data);
|
this.carriers[lang].data.push(response.data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createCarrierData = {
|
this.createCarrierData = {
|
||||||
city_id: 0,
|
city_id: 0,
|
||||||
logo: "",
|
preview_media: "",
|
||||||
|
video_preview: "",
|
||||||
main_color: "",
|
main_color: "",
|
||||||
left_color: "",
|
left_color: "",
|
||||||
right_color: "",
|
right_color: "",
|
||||||
ru: {
|
ru: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -278,36 +283,38 @@ class CarrierStore {
|
|||||||
ru: {
|
ru: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
full_name: "",
|
full_name: "",
|
||||||
short_name: "",
|
short_name: "",
|
||||||
slogan: "",
|
|
||||||
},
|
},
|
||||||
city_id: 0,
|
city_id: 0,
|
||||||
logo: "",
|
preview_media: "",
|
||||||
|
video_preview: "",
|
||||||
main_color: "",
|
main_color: "",
|
||||||
left_color: "",
|
left_color: "",
|
||||||
right_color: "",
|
right_color: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setEditCarrierMedia = (
|
||||||
|
field: "preview_media" | "video_preview",
|
||||||
|
mediaId: string
|
||||||
|
) => {
|
||||||
|
this.editCarrierData[field] = mediaId;
|
||||||
|
};
|
||||||
|
|
||||||
setEditCarrierData = (
|
setEditCarrierData = (
|
||||||
fullName: string,
|
fullName: string,
|
||||||
shortName: string,
|
shortName: string,
|
||||||
cityId: number,
|
cityId: number,
|
||||||
slogan: string,
|
|
||||||
logoId: string,
|
|
||||||
language: Language,
|
language: Language,
|
||||||
colors?: { main_color?: string; left_color?: string; right_color?: string }
|
colors?: { main_color?: string; left_color?: string; right_color?: string }
|
||||||
) => {
|
) => {
|
||||||
this.editCarrierData.city_id = cityId;
|
this.editCarrierData.city_id = cityId;
|
||||||
this.editCarrierData.logo = logoId;
|
|
||||||
if (colors) {
|
if (colors) {
|
||||||
if (colors.main_color !== undefined) this.editCarrierData.main_color = colors.main_color;
|
if (colors.main_color !== undefined) this.editCarrierData.main_color = colors.main_color;
|
||||||
if (colors.left_color !== undefined) this.editCarrierData.left_color = colors.left_color;
|
if (colors.left_color !== undefined) this.editCarrierData.left_color = colors.left_color;
|
||||||
@@ -316,7 +323,6 @@ class CarrierStore {
|
|||||||
this.editCarrierData[language] = {
|
this.editCarrierData[language] = {
|
||||||
full_name: fullName,
|
full_name: fullName,
|
||||||
short_name: shortName,
|
short_name: shortName,
|
||||||
slogan: slogan,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -327,10 +333,10 @@ class CarrierStore {
|
|||||||
...this.editCarrierData[lang],
|
...this.editCarrierData[lang],
|
||||||
full_name: (this.editCarrierData[lang].full_name || "").trim(),
|
full_name: (this.editCarrierData[lang].full_name || "").trim(),
|
||||||
short_name: (this.editCarrierData[lang].short_name || "").trim(),
|
short_name: (this.editCarrierData[lang].short_name || "").trim(),
|
||||||
slogan: (this.editCarrierData[lang].slogan || "").trim(),
|
|
||||||
city: cityName,
|
city: cityName,
|
||||||
city_id: this.editCarrierData.city_id,
|
city_id: this.editCarrierData.city_id,
|
||||||
...(this.editCarrierData.logo ? { logo: this.editCarrierData.logo } : {}),
|
preview_media: this.editCarrierData.preview_media || null,
|
||||||
|
video_preview: this.editCarrierData.video_preview || null,
|
||||||
...(this.editCarrierData.main_color ? { main_color: this.editCarrierData.main_color } : {}),
|
...(this.editCarrierData.main_color ? { main_color: this.editCarrierData.main_color } : {}),
|
||||||
...(this.editCarrierData.left_color ? { left_color: this.editCarrierData.left_color } : {}),
|
...(this.editCarrierData.left_color ? { left_color: this.editCarrierData.left_color } : {}),
|
||||||
...(this.editCarrierData.right_color ? { right_color: this.editCarrierData.right_color } : {}),
|
...(this.editCarrierData.right_color ? { right_color: this.editCarrierData.right_color } : {}),
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export type Route = {
|
|||||||
route_sys_number: string;
|
route_sys_number: string;
|
||||||
scale_max: number;
|
scale_max: number;
|
||||||
scale_min: number;
|
scale_min: number;
|
||||||
video_preview: string;
|
|
||||||
video_timer: number;
|
video_timer: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -154,21 +153,16 @@ class RouteStore {
|
|||||||
route_sys_number: "",
|
route_sys_number: "",
|
||||||
scale_max: 0,
|
scale_max: 0,
|
||||||
scale_min: 0,
|
scale_min: 0,
|
||||||
video_preview: "" as string | undefined,
|
|
||||||
video_timer: 420,
|
video_timer: 420,
|
||||||
};
|
};
|
||||||
|
|
||||||
setEditRouteData = (data: any) => {
|
setEditRouteData = (data: any) => {
|
||||||
this.editRouteData = { ...this.editRouteData, ...data };
|
const routeData = { ...data };
|
||||||
|
delete routeData.video_preview;
|
||||||
|
this.editRouteData = { ...this.editRouteData, ...routeData };
|
||||||
};
|
};
|
||||||
|
|
||||||
editRoute = async (id: number) => {
|
editRoute = async (id: number) => {
|
||||||
if (
|
|
||||||
!this.editRouteData.video_preview ||
|
|
||||||
isMediaIdEmpty(this.editRouteData.video_preview)
|
|
||||||
) {
|
|
||||||
delete this.editRouteData.video_preview;
|
|
||||||
}
|
|
||||||
if (!this.editRouteData.icon || isMediaIdEmpty(this.editRouteData.icon)) {
|
if (!this.editRouteData.icon || isMediaIdEmpty(this.editRouteData.icon)) {
|
||||||
delete (this.editRouteData as any).icon;
|
delete (this.editRouteData as any).icon;
|
||||||
}
|
}
|
||||||
@@ -180,6 +174,7 @@ class RouteStore {
|
|||||||
center_latitude: parseFloat(this.editRouteData.center_latitude),
|
center_latitude: parseFloat(this.editRouteData.center_latitude),
|
||||||
center_longitude: parseFloat(this.editRouteData.center_longitude),
|
center_longitude: parseFloat(this.editRouteData.center_longitude),
|
||||||
};
|
};
|
||||||
|
delete dataToSend.video_preview;
|
||||||
if (
|
if (
|
||||||
this.editRouteData.governor_appeal === 0 ||
|
this.editRouteData.governor_appeal === 0 ||
|
||||||
!this.editRouteData.governor_appeal
|
!this.editRouteData.governor_appeal
|
||||||
|
|||||||
40
src/shared/ui/PreviewBackgroundToggle/index.tsx
Normal file
40
src/shared/ui/PreviewBackgroundToggle/index.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
|
import { Contrast } from "lucide-react";
|
||||||
|
|
||||||
|
interface PreviewBackgroundToggleProps {
|
||||||
|
dark: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PreviewBackgroundToggle = ({
|
||||||
|
dark,
|
||||||
|
onToggle,
|
||||||
|
}: PreviewBackgroundToggleProps) => (
|
||||||
|
<Tooltip title={dark ? "Сделать фон белым" : "Сделать фон чёрным"}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
aria-label={dark ? "Сделать фон белым" : "Сделать фон чёрным"}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
onToggle();
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 8,
|
||||||
|
left: 8,
|
||||||
|
zIndex: 2,
|
||||||
|
color: dark ? "#fff" : "#000",
|
||||||
|
backgroundColor: dark
|
||||||
|
? "rgba(255, 255, 255, 0.16)"
|
||||||
|
: "rgba(255, 255, 255, 0.8)",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: dark
|
||||||
|
? "rgba(255, 255, 255, 0.28)"
|
||||||
|
: "rgba(255, 255, 255, 1)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Contrast size={18} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
@@ -6,3 +6,4 @@ export * from "./AnimatedCircleButton";
|
|||||||
export * from "./LoadingSpinner";
|
export * from "./LoadingSpinner";
|
||||||
export * from "./MultiSelect";
|
export * from "./MultiSelect";
|
||||||
export * from "./SearchInput";
|
export * from "./SearchInput";
|
||||||
|
export * from "./PreviewBackgroundToggle";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useRef, DragEvent } from "react";
|
import React, { useRef, useState, DragEvent } from "react";
|
||||||
import { Paper, Box, Typography, Button, Tooltip } from "@mui/material";
|
import { Paper, Box, Typography, Button, Tooltip } from "@mui/material";
|
||||||
import { X, Info, Plus } from "lucide-react";
|
import { X, Info, Plus } from "lucide-react";
|
||||||
import { editSightStore } from "@shared";
|
import { editSightStore, PreviewBackgroundToggle } from "@shared";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
interface ImageUploadCardProps {
|
interface ImageUploadCardProps {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -33,6 +33,7 @@ export const ImageUploadCard: React.FC<ImageUploadCardProps> = ({
|
|||||||
tooltipText,
|
tooltipText,
|
||||||
}) => {
|
}) => {
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const [isPreviewBackgroundDark, setIsPreviewBackgroundDark] = useState(false);
|
||||||
const { setFileToUpload } = editSightStore;
|
const { setFileToUpload } = editSightStore;
|
||||||
|
|
||||||
const handleZoneClick = () => {
|
const handleZoneClick = () => {
|
||||||
@@ -124,9 +125,21 @@ export const ImageUploadCard: React.FC<ImageUploadCardProps> = ({
|
|||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
mb: 1,
|
mb: 1,
|
||||||
cursor: imageUrl ? "pointer" : "default",
|
cursor: imageUrl ? "pointer" : "default",
|
||||||
|
backgroundColor: imageUrl
|
||||||
|
? isPreviewBackgroundDark
|
||||||
|
? "#000"
|
||||||
|
: "#fff"
|
||||||
|
: "transparent",
|
||||||
|
transition: "background-color 150ms ease",
|
||||||
}}
|
}}
|
||||||
onClick={onImageClick}
|
onClick={onImageClick}
|
||||||
>
|
>
|
||||||
|
{imageUrl && (
|
||||||
|
<PreviewBackgroundToggle
|
||||||
|
dark={isPreviewBackgroundDark}
|
||||||
|
onToggle={() => setIsPreviewBackgroundDark((value) => !value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{imageUrl && (
|
{imageUrl && (
|
||||||
<button
|
<button
|
||||||
className="absolute top-2 right-2"
|
className="absolute top-2 right-2"
|
||||||
|
|||||||
Reference in New Issue
Block a user