feat: Add preview_video
for sights
This commit is contained in:
@ -50,7 +50,6 @@ export const CityListPage = observer(() => {
|
||||
}
|
||||
|
||||
setRows(newRows2 || []);
|
||||
console.log(newRows2);
|
||||
}, [cities, countryStore.countries, language, isLoading]);
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
|
@ -17,6 +17,7 @@ export const MEDIA_TYPE_VALUES = {
|
||||
watermark_rd: 4,
|
||||
panorama: 5,
|
||||
model: 6,
|
||||
video_preview: 2,
|
||||
};
|
||||
|
||||
export const RU_COUNTRIES = [
|
||||
|
@ -36,7 +36,13 @@ interface UploadMediaDialogProps {
|
||||
media_type: number;
|
||||
}) => void;
|
||||
afterUploadSight?: (id: string) => void;
|
||||
hardcodeType?: "thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null;
|
||||
hardcodeType?:
|
||||
| "thumbnail"
|
||||
| "watermark_lu"
|
||||
| "watermark_rd"
|
||||
| "image"
|
||||
| "video_preview"
|
||||
| null;
|
||||
contextObjectName?: string;
|
||||
contextType?:
|
||||
| "sight"
|
||||
@ -47,6 +53,7 @@ interface UploadMediaDialogProps {
|
||||
| "station";
|
||||
isArticle?: boolean;
|
||||
articleName?: string;
|
||||
initialFile?: File; // <--- добавлено
|
||||
}
|
||||
|
||||
export const UploadMediaDialog = observer(
|
||||
@ -60,6 +67,7 @@ export const UploadMediaDialog = observer(
|
||||
|
||||
isArticle,
|
||||
articleName,
|
||||
initialFile, // <--- добавлено
|
||||
}: UploadMediaDialogProps) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@ -74,6 +82,17 @@ export const UploadMediaDialog = observer(
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialFile) {
|
||||
setMediaFile(initialFile);
|
||||
setMediaFilename(initialFile.name);
|
||||
setAvailableMediaTypes([2]);
|
||||
setMediaType(2);
|
||||
setMediaUrl(URL.createObjectURL(initialFile));
|
||||
setMediaName(initialFile.name.replace(/\.[^/.]+$/, ""));
|
||||
}
|
||||
}, [initialFile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (fileToUpload) {
|
||||
setMediaFile(fileToUpload);
|
||||
@ -226,6 +245,10 @@ export const UploadMediaDialog = observer(
|
||||
}
|
||||
}
|
||||
setSuccess(true);
|
||||
// Закрываем модальное окно после успешного сохранения
|
||||
setTimeout(() => {
|
||||
handleClose();
|
||||
}, 1000); // Небольшая задержка, чтобы пользователь увидел сообщение об успехе
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Failed to save media");
|
||||
} finally {
|
||||
@ -333,10 +356,15 @@ export const UploadMediaDialog = observer(
|
||||
<Box className="flex flex-col gap-2 self-end">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
sx={{
|
||||
backgroundColor: isLoading ? "#9e9e9e" : "#4caf50",
|
||||
"&:hover": {
|
||||
backgroundColor: isLoading ? "#9e9e9e" : "#45a049",
|
||||
},
|
||||
}}
|
||||
startIcon={
|
||||
isLoading ? (
|
||||
<CircularProgress size={16} />
|
||||
<CircularProgress size={16} color="inherit" />
|
||||
) : (
|
||||
<Save size={16} />
|
||||
)
|
||||
@ -344,7 +372,7 @@ export const UploadMediaDialog = observer(
|
||||
onClick={handleSave}
|
||||
disabled={isLoading || (!mediaName && !mediaFilename)}
|
||||
>
|
||||
Сохранить
|
||||
{isLoading ? "Сохранение..." : "Сохранить"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -12,6 +12,7 @@ class DevicesStore {
|
||||
|
||||
getDevices = async () => {
|
||||
const response = await authInstance.get(`${API_URL}/devices/connected`);
|
||||
|
||||
runInAction(() => {
|
||||
this.devices = response.data;
|
||||
});
|
||||
|
@ -174,6 +174,7 @@ export const DevicesTable = observer(() => {
|
||||
setSelectedDevice(uuid); // Sets the device in the store, useful for context elsewhere
|
||||
try {
|
||||
await authInstance.post(`/devices/${uuid}/request-status`);
|
||||
await getVehicles();
|
||||
await getDevices(); // Refresh devices to show updated status
|
||||
} catch (error) {
|
||||
console.error(`Error requesting status for device ${uuid}:`, error);
|
||||
@ -398,7 +399,6 @@ export const DevicesTable = observer(() => {
|
||||
devices.find((device) => device === row.device_uuid)
|
||||
) {
|
||||
await handleReloadStatus(row.device_uuid);
|
||||
await getDevices();
|
||||
toast.success("Статус устройства обновлен");
|
||||
} else {
|
||||
toast.error("Нет связи с устройством");
|
||||
|
@ -59,7 +59,6 @@ export const Layout: React.FC<LayoutProps> = observer(({ children }) => {
|
||||
<div className="flex gap-2 items-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
{(() => {
|
||||
console.log(authStore.payload);
|
||||
return (
|
||||
<>
|
||||
<p className=" text-white">
|
||||
|
@ -5,6 +5,10 @@ import {
|
||||
Autocomplete,
|
||||
MenuItem,
|
||||
Menu as MuiMenu,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
BackButton,
|
||||
@ -20,7 +24,12 @@ import {
|
||||
UploadMediaDialog,
|
||||
MEDIA_TYPE_VALUES,
|
||||
} from "@shared";
|
||||
import { ImageUploadCard, LanguageSwitcher } from "@widgets";
|
||||
import {
|
||||
ImageUploadCard,
|
||||
LanguageSwitcher,
|
||||
VideoPreviewCard,
|
||||
MediaViewer,
|
||||
} from "@widgets";
|
||||
import { Save } from "lucide-react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
@ -45,13 +54,15 @@ export const CreateInformationTab = observer(
|
||||
// Menu state for each media button
|
||||
const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const [activeMenuType, setActiveMenuType] = useState<
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | null
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null
|
||||
>(null);
|
||||
const [isAddMediaOpen, setIsAddMediaOpen] = useState(false);
|
||||
const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false);
|
||||
const [hardcodeType, setHardcodeType] = useState<
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | null
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null
|
||||
>(null);
|
||||
|
||||
useEffect(() => {}, [hardcodeType]);
|
||||
// const handleMenuOpen = (
|
||||
// event: React.MouseEvent<HTMLElement>,
|
||||
// type: "thumbnail" | "watermark_lu" | "watermark_rd"
|
||||
@ -100,7 +111,7 @@ export const CreateInformationTab = observer(
|
||||
media_name?: string;
|
||||
media_type: number;
|
||||
},
|
||||
type: "thumbnail" | "watermark_lu" | "watermark_rd"
|
||||
type: "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview"
|
||||
) => {
|
||||
handleChange({
|
||||
[type]: media.id,
|
||||
@ -108,6 +119,12 @@ export const CreateInformationTab = observer(
|
||||
setActiveMenuType(null);
|
||||
};
|
||||
|
||||
const handleVideoPreviewClick = () => {
|
||||
if (sight.video_preview && sight.video_preview !== "") {
|
||||
setIsVideoPreviewOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TabPanel value={value} index={index}>
|
||||
@ -329,6 +346,29 @@ export const CreateInformationTab = observer(
|
||||
setHardcodeType("watermark_rd");
|
||||
}}
|
||||
/>
|
||||
|
||||
<VideoPreviewCard
|
||||
title="Видео превью"
|
||||
videoId={sight.video_preview}
|
||||
onVideoClick={handleVideoPreviewClick}
|
||||
onDeleteVideoClick={() => {
|
||||
handleChange({
|
||||
video_preview: null,
|
||||
});
|
||||
}}
|
||||
onSelectVideoClick={(file) => {
|
||||
if (file) {
|
||||
// Если передан файл, открываем диалог загрузки медиа
|
||||
createSightStore.setFileToUpload(file);
|
||||
setActiveMenuType("video_preview");
|
||||
setIsUploadMediaOpen(true);
|
||||
} else {
|
||||
// Если файл не передан, открываем диалог выбора существующих медиа
|
||||
setActiveMenuType("video_preview");
|
||||
setIsAddMediaOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -390,7 +430,9 @@ export const CreateInformationTab = observer(
|
||||
setActiveMenuType(null);
|
||||
}}
|
||||
onSelectMedia={(media) => {
|
||||
handleMediaSelect(media, activeMenuType ?? "thumbnail");
|
||||
if (activeMenuType) {
|
||||
handleMediaSelect(media, activeMenuType);
|
||||
}
|
||||
}}
|
||||
mediaType={
|
||||
activeMenuType
|
||||
@ -413,14 +455,49 @@ export const CreateInformationTab = observer(
|
||||
contextObjectName={sight[language].name}
|
||||
contextType="sight"
|
||||
afterUpload={(media) => {
|
||||
handleChange({
|
||||
[activeMenuType ?? "thumbnail"]: media.id,
|
||||
});
|
||||
if (activeMenuType === "video_preview") {
|
||||
handleChange({
|
||||
video_preview: media.id,
|
||||
});
|
||||
} else {
|
||||
handleChange({
|
||||
[activeMenuType ?? "thumbnail"]: media.id,
|
||||
});
|
||||
}
|
||||
setActiveMenuType(null);
|
||||
setIsUploadMediaOpen(false);
|
||||
}}
|
||||
hardcodeType={hardcodeType}
|
||||
hardcodeType={activeMenuType}
|
||||
initialFile={createSightStore.fileToUpload || undefined}
|
||||
/>
|
||||
|
||||
{/* Модальное окно предпросмотра видео */}
|
||||
{sight.video_preview && sight.video_preview !== "" && (
|
||||
<Dialog
|
||||
open={isVideoPreviewOpen}
|
||||
onClose={() => setIsVideoPreviewOpen(false)}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>Предпросмотр видео</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box className="flex justify-center items-center p-4">
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: sight.video_preview,
|
||||
media_type: 2,
|
||||
filename: "video_preview",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setIsVideoPreviewOpen(false)}>
|
||||
Закрыть
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,10 @@ import {
|
||||
Autocomplete,
|
||||
MenuItem,
|
||||
Menu as MuiMenu,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
BackButton,
|
||||
@ -20,7 +24,12 @@ import {
|
||||
UploadMediaDialog,
|
||||
MEDIA_TYPE_VALUES,
|
||||
} from "@shared";
|
||||
import { ImageUploadCard, LanguageSwitcher } from "@widgets";
|
||||
import {
|
||||
ImageUploadCard,
|
||||
LanguageSwitcher,
|
||||
VideoPreviewCard,
|
||||
MediaViewer,
|
||||
} from "@widgets";
|
||||
import { Save } from "lucide-react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
@ -45,13 +54,17 @@ export const InformationTab = observer(
|
||||
// Menu state for each media button
|
||||
const [menuAnchorEl, setMenuAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const [activeMenuType, setActiveMenuType] = useState<
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | null
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null
|
||||
>(null);
|
||||
const [isAddMediaOpen, setIsAddMediaOpen] = useState(false);
|
||||
const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false);
|
||||
const [hardcodeType, setHardcodeType] = useState<
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | null
|
||||
"thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null
|
||||
>(null);
|
||||
const { cities } = cityStore;
|
||||
|
||||
useEffect(() => {}, [hardcodeType]);
|
||||
|
||||
useEffect(() => {
|
||||
// Показывать только при инициализации (не менять при ошибках пользователя)
|
||||
if (sight.common.latitude !== 0 || sight.common.longitude !== 0) {
|
||||
@ -74,22 +87,28 @@ export const InformationTab = observer(
|
||||
handleMenuClose();
|
||||
};
|
||||
|
||||
const handleMediaSelect = (media: {
|
||||
id: string;
|
||||
filename: string;
|
||||
media_name?: string;
|
||||
media_type: number;
|
||||
}) => {
|
||||
if (!activeMenuType) return;
|
||||
const handleMediaSelect = (
|
||||
media: {
|
||||
id: string;
|
||||
filename: string;
|
||||
media_name?: string;
|
||||
media_type: number;
|
||||
},
|
||||
type: "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview"
|
||||
) => {
|
||||
handleChange(
|
||||
language as Language,
|
||||
{
|
||||
[activeMenuType ?? "thumbnail"]: media.id,
|
||||
[type]: media.id,
|
||||
},
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
setIsUploadMediaOpen(false);
|
||||
const handleVideoPreviewClick = () => {
|
||||
if (sight.common.video_preview && sight.common.video_preview !== "") {
|
||||
setIsVideoPreviewOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (
|
||||
@ -337,6 +356,33 @@ export const InformationTab = observer(
|
||||
setHardcodeType("watermark_rd");
|
||||
}}
|
||||
/>
|
||||
|
||||
<VideoPreviewCard
|
||||
title="Видео превью"
|
||||
videoId={sight.common.video_preview}
|
||||
onVideoClick={handleVideoPreviewClick}
|
||||
onDeleteVideoClick={() => {
|
||||
handleChange(
|
||||
language as Language,
|
||||
{
|
||||
video_preview: null,
|
||||
},
|
||||
true
|
||||
);
|
||||
}}
|
||||
onSelectVideoClick={(file) => {
|
||||
if (file) {
|
||||
// Если передан файл, открываем диалог загрузки медиа
|
||||
editSightStore.setFileToUpload(file);
|
||||
setActiveMenuType("video_preview");
|
||||
setIsUploadMediaOpen(true);
|
||||
} else {
|
||||
// Если файл не передан, открываем диалог выбора существующих медиа
|
||||
setActiveMenuType("video_preview");
|
||||
setIsAddMediaOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
@ -395,8 +441,13 @@ export const InformationTab = observer(
|
||||
open={isAddMediaOpen}
|
||||
onClose={() => {
|
||||
setIsAddMediaOpen(false);
|
||||
setActiveMenuType(null);
|
||||
}}
|
||||
onSelectMedia={(media) => {
|
||||
if (activeMenuType) {
|
||||
handleMediaSelect(media, activeMenuType);
|
||||
}
|
||||
}}
|
||||
onSelectMedia={handleMediaSelect}
|
||||
mediaType={
|
||||
activeMenuType
|
||||
? MEDIA_TYPE_VALUES[
|
||||
@ -412,23 +463,62 @@ export const InformationTab = observer(
|
||||
contextObjectName={sight[language].name}
|
||||
contextType="sight"
|
||||
afterUpload={(media) => {
|
||||
handleChange(
|
||||
language as Language,
|
||||
{
|
||||
[activeMenuType ?? "thumbnail"]: media.id,
|
||||
},
|
||||
true
|
||||
);
|
||||
if (activeMenuType === "video_preview") {
|
||||
handleChange(
|
||||
language as Language,
|
||||
{
|
||||
video_preview: media.id,
|
||||
},
|
||||
true
|
||||
);
|
||||
} else {
|
||||
handleChange(
|
||||
language as Language,
|
||||
{
|
||||
[activeMenuType ?? "thumbnail"]: media.id,
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
setActiveMenuType(null);
|
||||
setIsUploadMediaOpen(false);
|
||||
}}
|
||||
hardcodeType={hardcodeType}
|
||||
hardcodeType={activeMenuType}
|
||||
initialFile={editSightStore.fileToUpload || undefined}
|
||||
/>
|
||||
<PreviewMediaDialog
|
||||
open={isPreviewMediaOpen}
|
||||
onClose={() => setIsPreviewMediaOpen(false)}
|
||||
mediaId={mediaId}
|
||||
/>
|
||||
|
||||
{/* Модальное окно предпросмотра видео */}
|
||||
{sight.common.video_preview && sight.common.video_preview !== "" && (
|
||||
<Dialog
|
||||
open={isVideoPreviewOpen}
|
||||
onClose={() => setIsVideoPreviewOpen(false)}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>Предпросмотр видео</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box className="flex justify-center items-center p-4">
|
||||
<MediaViewer
|
||||
media={{
|
||||
id: sight.common.video_preview,
|
||||
media_type: 2,
|
||||
filename: "video_preview",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setIsVideoPreviewOpen(false)}>
|
||||
Закрыть
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
203
src/widgets/VideoPreviewCard/index.tsx
Normal file
203
src/widgets/VideoPreviewCard/index.tsx
Normal file
@ -0,0 +1,203 @@
|
||||
import React, { useRef, useState, DragEvent, useEffect } from "react";
|
||||
import { Paper, Box, Typography, Button, Tooltip } from "@mui/material";
|
||||
import { X, Info, Plus, Play } from "lucide-react";
|
||||
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
interface VideoPreviewCardProps {
|
||||
title: string;
|
||||
videoId: string | null | undefined;
|
||||
onVideoClick: () => void;
|
||||
onDeleteVideoClick: () => void;
|
||||
onSelectVideoClick: (file?: File) => void;
|
||||
tooltipText?: string;
|
||||
}
|
||||
|
||||
export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({
|
||||
title,
|
||||
videoId,
|
||||
onVideoClick,
|
||||
onDeleteVideoClick,
|
||||
onSelectVideoClick,
|
||||
tooltipText,
|
||||
}) => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [isDragOver, setIsDragOver] = useState(false);
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
useEffect(() => {}, [isDragOver]);
|
||||
// --- Click to select file ---
|
||||
const handleZoneClick = () => {
|
||||
// Trigger the hidden file input click
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleFileInputChange = async (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (file) {
|
||||
if (file.type.startsWith("video/")) {
|
||||
// Открываем диалог загрузки медиа с файлом видео
|
||||
onSelectVideoClick(file);
|
||||
} else {
|
||||
toast.error("Пожалуйста, выберите видео файл");
|
||||
}
|
||||
}
|
||||
// Reset the input value so selecting the same file again triggers change
|
||||
event.target.value = "";
|
||||
};
|
||||
|
||||
// --- Drag and Drop Handlers ---
|
||||
const handleDragOver = (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault(); // Crucial to allow a drop
|
||||
event.stopPropagation();
|
||||
setIsDragOver(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setIsDragOver(false);
|
||||
};
|
||||
|
||||
const handleDrop = async (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault(); // Crucial to allow a drop
|
||||
event.stopPropagation();
|
||||
setIsDragOver(false);
|
||||
|
||||
const files = event.dataTransfer.files;
|
||||
if (files && files.length > 0) {
|
||||
const file = files[0];
|
||||
if (file.type.startsWith("video/")) {
|
||||
// Открываем диалог загрузки медиа с файлом видео
|
||||
onSelectVideoClick(file);
|
||||
} else {
|
||||
toast.error("Пожалуйста, выберите видео файл");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={2}
|
||||
sx={{
|
||||
padding: 2,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: 1,
|
||||
flex: 1,
|
||||
minWidth: 150,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography variant="subtitle2" gutterBottom sx={{ mb: 0, mr: 0.5 }}>
|
||||
{title}
|
||||
</Typography>
|
||||
{tooltipText && (
|
||||
<Tooltip title={tooltipText}>
|
||||
<Info size={16} color="gray" style={{ cursor: "pointer" }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
width: "200px",
|
||||
height: "200px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: 1,
|
||||
mb: 1,
|
||||
cursor: videoId ? "pointer" : "default",
|
||||
}}
|
||||
onClick={onVideoClick}
|
||||
>
|
||||
{videoId && (
|
||||
<button
|
||||
className="absolute top-2 right-2 z-10"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDeleteVideoClick();
|
||||
}}
|
||||
>
|
||||
<X color="red" />
|
||||
</button>
|
||||
)}
|
||||
{videoId ? (
|
||||
<Box sx={{ position: "relative", width: "100%", height: "100%" }}>
|
||||
<video
|
||||
src={`${
|
||||
import.meta.env.VITE_KRBL_MEDIA
|
||||
}${videoId}/download?token=${token}`}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
borderRadius: 4,
|
||||
}}
|
||||
muted
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
borderRadius: "50%",
|
||||
width: 40,
|
||||
height: 40,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Play size={20} color="white" />
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<div className="w-full flex flex-col items-center justify-center gap-3">
|
||||
<div
|
||||
className="flex flex-col p-5 items-center justify-center gap-3"
|
||||
style={{
|
||||
border: "2px dashed #ccc",
|
||||
borderRadius: 1,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={handleZoneClick} // Click handler for the zone
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<p className="text-center">Перетащите файл</p>
|
||||
</div>
|
||||
|
||||
<p>или</p>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<Plus color="white" size={18} />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation(); // Prevent `handleZoneClick` from firing
|
||||
onSelectVideoClick(); // This button triggers the media selection dialog
|
||||
}}
|
||||
>
|
||||
Выбрать файл
|
||||
</Button>
|
||||
{/* Hidden file input */}
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileInputChange}
|
||||
style={{ display: "none" }}
|
||||
accept="video/*" // Accept only video files
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
};
|
@ -12,6 +12,7 @@ export * from "./MediaArea";
|
||||
export * from "./ModelViewer3D";
|
||||
export * from "./MediaAreaForSight";
|
||||
export * from "./ImageUploadCard";
|
||||
export * from "./VideoPreviewCard";
|
||||
export * from "./LeaveAgree";
|
||||
export * from "./DeleteModal";
|
||||
export * from "./SnapshotRestore";
|
||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user