208 lines
5.6 KiB
TypeScript
208 lines
5.6 KiB
TypeScript
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;
|
||
className?: string;
|
||
}
|
||
|
||
export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({
|
||
title,
|
||
videoId,
|
||
onVideoClick,
|
||
onDeleteVideoClick,
|
||
onSelectVideoClick,
|
||
tooltipText,
|
||
className,
|
||
}) => {
|
||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||
const [isDragOver, setIsDragOver] = useState(false);
|
||
const token = localStorage.getItem("token");
|
||
|
||
useEffect(() => {}, [isDragOver]);
|
||
|
||
const handleZoneClick = () => {
|
||
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("Пожалуйста, выберите видео файл");
|
||
}
|
||
}
|
||
|
||
event.target.value = "";
|
||
};
|
||
|
||
const handleDragOver = (event: DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
setIsDragOver(true);
|
||
};
|
||
|
||
const handleDragLeave = (event: DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
setIsDragOver(false);
|
||
};
|
||
|
||
const handleDrop = async (event: DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
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,
|
||
width: "min-content",
|
||
mx: "auto",
|
||
}}
|
||
className={className}
|
||
>
|
||
<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%" }}
|
||
className={className}
|
||
>
|
||
<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}
|
||
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();
|
||
onSelectVideoClick();
|
||
}}
|
||
>
|
||
Выбрать файл
|
||
</Button>
|
||
{/* Hidden file input */}
|
||
<input
|
||
type="file"
|
||
ref={fileInputRef}
|
||
onChange={handleFileInputChange}
|
||
style={{ display: "none" }}
|
||
accept="video/*"
|
||
/>
|
||
</div>
|
||
)}
|
||
</Box>
|
||
</Paper>
|
||
);
|
||
};
|