136 lines
4.3 KiB
TypeScript
136 lines
4.3 KiB
TypeScript
import { Box, Button } from "@mui/material";
|
||
import { MediaViewer } from "@widgets";
|
||
import { PreviewMediaDialog } from "@shared";
|
||
import { X, Upload } from "lucide-react";
|
||
import { observer } from "mobx-react-lite";
|
||
import { useState, DragEvent, useRef } from "react";
|
||
|
||
export const MediaArea = observer(
|
||
({
|
||
articleId,
|
||
mediaIds,
|
||
deleteMedia,
|
||
onFilesDrop, // 👈 Проп для обработки загруженных файлов
|
||
setSelectMediaDialogOpen,
|
||
}: {
|
||
articleId: number;
|
||
mediaIds: { id: string; media_type: number; filename: string }[];
|
||
deleteMedia: (id: number, media_id: string) => void;
|
||
onFilesDrop?: (files: File[]) => void;
|
||
setSelectMediaDialogOpen: (open: boolean) => void;
|
||
}) => {
|
||
const [mediaModal, setMediaModal] = useState<boolean>(false);
|
||
const [mediaId, setMediaId] = useState<string>("");
|
||
const [isDragging, setIsDragging] = useState(false);
|
||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||
|
||
const handleMediaModal = (mediaId: string) => {
|
||
setMediaModal(true);
|
||
setMediaId(mediaId);
|
||
};
|
||
|
||
const handleDrop = (e: DragEvent<HTMLDivElement>) => {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
setIsDragging(false);
|
||
|
||
const files = Array.from(e.dataTransfer.files);
|
||
if (files.length && onFilesDrop) {
|
||
onFilesDrop(files);
|
||
}
|
||
};
|
||
|
||
const handleDragOver = (e: DragEvent<HTMLDivElement>) => {
|
||
e.preventDefault();
|
||
setIsDragging(true);
|
||
};
|
||
|
||
const handleDragLeave = () => {
|
||
setIsDragging(false);
|
||
};
|
||
|
||
const handleClick = () => {
|
||
fileInputRef.current?.click();
|
||
};
|
||
|
||
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||
const files = Array.from(event.target.files || []);
|
||
if (files.length && onFilesDrop) {
|
||
onFilesDrop(files);
|
||
}
|
||
// Сбрасываем значение input, чтобы можно было выбрать тот же файл снова
|
||
event.target.value = "";
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<input
|
||
type="file"
|
||
ref={fileInputRef}
|
||
onChange={handleFileSelect}
|
||
accept="image/*,video/*,.glb,.gltf"
|
||
multiple
|
||
style={{ display: "none" }}
|
||
/>
|
||
<Box className="w-full flex flex-col items-center justify-center border rounded-md p-4">
|
||
<div className="w-full flex flex-col items-center justify-center">
|
||
<div
|
||
className={`w-full h-40 flex flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 ${
|
||
isDragging ? "bg-blue-100 border-blue-400" : ""
|
||
}`}
|
||
onDrop={handleDrop}
|
||
onDragOver={handleDragOver}
|
||
onDragLeave={handleDragLeave}
|
||
onClick={handleClick}
|
||
>
|
||
<Upload size={32} className="mb-2" />
|
||
Перетащите медиа файлы сюда или нажмите для выбора
|
||
</div>
|
||
<div>или</div>
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
onClick={() => setSelectMediaDialogOpen(true)}
|
||
>
|
||
Выбрать существующие медиа файлы
|
||
</Button>
|
||
</div>
|
||
|
||
<div className="w-full flex flex-start flex-wrap gap-2 mt-4">
|
||
{mediaIds.map((m) => (
|
||
<button
|
||
className="relative w-40 h-40"
|
||
key={m.id}
|
||
onClick={() => handleMediaModal(m.id)}
|
||
>
|
||
<MediaViewer
|
||
media={{
|
||
id: m.id,
|
||
media_type: m.media_type,
|
||
filename: m.filename,
|
||
}}
|
||
/>
|
||
<button
|
||
className="absolute top-2 right-2"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
deleteMedia(articleId, m.id);
|
||
}}
|
||
>
|
||
<X size={16} color="red" />
|
||
</button>
|
||
</button>
|
||
))}
|
||
</div>
|
||
</Box>
|
||
|
||
<PreviewMediaDialog
|
||
open={mediaModal}
|
||
onClose={() => setMediaModal(false)}
|
||
mediaId={mediaId}
|
||
/>
|
||
</>
|
||
);
|
||
}
|
||
);
|