230 lines
7.8 KiB
TypeScript
230 lines
7.8 KiB
TypeScript
import { Media, mediaStore } from "@shared";
|
||
import { observer } from "mobx-react-lite";
|
||
import { useEffect, useState } from "react";
|
||
import {
|
||
Dialog,
|
||
DialogTitle,
|
||
DialogContent,
|
||
DialogActions,
|
||
Button,
|
||
TextField,
|
||
List,
|
||
ListItemButton,
|
||
ListItemText,
|
||
Paper,
|
||
Typography,
|
||
InputAdornment,
|
||
} from "@mui/material";
|
||
import { Search } from "lucide-react";
|
||
import { MediaViewer } from "@widgets";
|
||
|
||
interface SelectMediaDialogProps {
|
||
open: boolean; // Corrected prop name
|
||
onClose: () => void;
|
||
onSelectMedia?: (media: {
|
||
id: string;
|
||
filename: string;
|
||
media_name?: string;
|
||
media_type: number;
|
||
}) => void; // Renamed from onSelectArticle
|
||
onSelectForSightMedia?: (mediaId: string) => void;
|
||
linkedMediaIds?: string[]; // Renamed from linkedArticleIds, assuming it refers to media already in use
|
||
mediaType?: number;
|
||
}
|
||
|
||
export const SelectMediaDialog = observer(
|
||
({
|
||
open, // Corrected prop name
|
||
onClose,
|
||
onSelectMedia, // Renamed prop
|
||
onSelectForSightMedia,
|
||
linkedMediaIds = [], // Default to empty array if not provided, renamed
|
||
mediaType,
|
||
}: SelectMediaDialogProps) => {
|
||
const { media, getMedia } = mediaStore;
|
||
const [searchQuery, setSearchQuery] = useState("");
|
||
const [hoveredMediaId, setHoveredMediaId] = useState<string | null>(null);
|
||
const [currentHoveredMedia, setCurrentHoveredMedia] =
|
||
useState<Media | null>(null);
|
||
|
||
useEffect(() => {
|
||
if (hoveredMediaId) {
|
||
setCurrentHoveredMedia(
|
||
media.find((m) => m.id === hoveredMediaId) ?? null
|
||
);
|
||
}
|
||
}, [hoveredMediaId]);
|
||
|
||
const handleClose = () => {
|
||
setHoveredMediaId(null);
|
||
setCurrentHoveredMedia(null);
|
||
onClose();
|
||
setSearchQuery("");
|
||
};
|
||
|
||
useEffect(() => {
|
||
getMedia();
|
||
}, [getMedia]);
|
||
|
||
// Keyboard event listener for "Enter" key to select hovered media
|
||
useEffect(() => {
|
||
const handleKeyPress = (event: KeyboardEvent) => {
|
||
if (event.key === "Enter") {
|
||
event.preventDefault(); // Prevent browser default action (e.g., form submission)
|
||
|
||
if (hoveredMediaId) {
|
||
const mediaItem = media.find((m) => m.id === hoveredMediaId);
|
||
if (mediaItem) {
|
||
if (onSelectForSightMedia) {
|
||
onSelectForSightMedia(mediaItem.id);
|
||
} else if (onSelectMedia) {
|
||
onSelectMedia(mediaItem);
|
||
}
|
||
}
|
||
handleClose();
|
||
}
|
||
}
|
||
};
|
||
|
||
window.addEventListener("keydown", handleKeyPress);
|
||
return () => {
|
||
window.removeEventListener("keydown", handleKeyPress);
|
||
};
|
||
}, [hoveredMediaId, onSelectMedia, onClose]); // Dependencies for keyboard listener
|
||
|
||
let filteredMedia = media
|
||
.filter((mediaItem) => !linkedMediaIds.includes(mediaItem.id)) // Use mediaItem to avoid name collision
|
||
.filter((mediaItem) =>
|
||
mediaItem.media_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||
);
|
||
|
||
if (mediaType) {
|
||
filteredMedia = filteredMedia.filter(
|
||
(mediaItem) => mediaItem.media_type === mediaType
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onClose={handleClose} maxWidth="lg" fullWidth>
|
||
<DialogTitle>Выберите существующее медиа</DialogTitle>
|
||
<DialogContent
|
||
className="flex gap-4"
|
||
dividers // Adds a divider below the title and above the actions
|
||
sx={{ height: "600px", display: "flex", flexDirection: "row" }} // Fixed height for DialogContent
|
||
>
|
||
<Paper className="w-[66%] flex flex-col" sx={{ p: 2 }}>
|
||
{" "}
|
||
{/* Added padding for consistency */}
|
||
<TextField
|
||
fullWidth
|
||
placeholder="Поиск медиа..." // Changed placeholder for clarity
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
sx={{ mb: 2, mt: 1 }}
|
||
InputProps={{
|
||
startAdornment: (
|
||
<InputAdornment position="start">
|
||
<Search size={20} />
|
||
</InputAdornment>
|
||
),
|
||
}}
|
||
/>
|
||
<List sx={{ flexGrow: 1, overflowY: "auto" }}>
|
||
{filteredMedia.length > 0 ? (
|
||
filteredMedia.map(
|
||
(
|
||
mediaItem // Use mediaItem to avoid confusion
|
||
) => (
|
||
<ListItemButton
|
||
key={mediaItem.id}
|
||
onClick={() => setHoveredMediaId(mediaItem.id)} // Call onSelectMedia
|
||
onDoubleClick={() => {
|
||
if (onSelectForSightMedia) {
|
||
onSelectForSightMedia(mediaItem.id);
|
||
} else if (onSelectMedia) {
|
||
onSelectMedia(mediaItem);
|
||
}
|
||
handleClose();
|
||
}}
|
||
selected={hoveredMediaId === mediaItem.id}
|
||
sx={{
|
||
borderRadius: 1,
|
||
mb: 0.5,
|
||
"&:hover": {
|
||
backgroundColor: "action.hover",
|
||
},
|
||
"&.Mui-selected": {
|
||
backgroundColor: "primary.main",
|
||
color: "primary.contrastText",
|
||
"&:hover": {
|
||
backgroundColor: "primary.dark",
|
||
},
|
||
},
|
||
}}
|
||
>
|
||
<ListItemText
|
||
primary={
|
||
mediaItem.media_name
|
||
? mediaItem.media_name
|
||
: mediaItem.filename
|
||
}
|
||
/>
|
||
</ListItemButton>
|
||
)
|
||
)
|
||
) : (
|
||
<Typography
|
||
sx={{ mt: 2, textAlign: "center" }}
|
||
color="text.secondary"
|
||
>
|
||
Медиа не найдено или все медиа уже прикреплены.
|
||
</Typography>
|
||
)}
|
||
</List>
|
||
</Paper>
|
||
{currentHoveredMedia !== null && hoveredMediaId !== null ? ( // Only render MediaViewer if currentHoveredMedia is found
|
||
<Paper className="w-[33%] h-[100%] flex justify-center items-center">
|
||
<MediaViewer
|
||
media={{
|
||
id: currentHoveredMedia.id,
|
||
media_type: currentHoveredMedia.media_type ?? 1, // Provide a default if media_type can be undefined
|
||
filename: currentHoveredMedia.filename,
|
||
}}
|
||
/>
|
||
</Paper>
|
||
) : (
|
||
<Paper className="w-[33%] h-[100%] flex justify-center items-center">
|
||
<Typography variant="body2" color="text.secondary">
|
||
Наведите на медиа в списке для предпросмотра.
|
||
</Typography>
|
||
</Paper>
|
||
)}
|
||
</DialogContent>
|
||
|
||
<DialogActions sx={{ p: 2 }}>
|
||
<Button onClick={handleClose}>Отмена</Button>
|
||
<Button
|
||
variant="contained"
|
||
onClick={() => {
|
||
if (hoveredMediaId) {
|
||
const mediaItem = media.find((m) => m.id === hoveredMediaId);
|
||
if (mediaItem) {
|
||
if (onSelectForSightMedia) {
|
||
onSelectForSightMedia(mediaItem.id);
|
||
} else if (onSelectMedia) {
|
||
onSelectMedia(mediaItem);
|
||
}
|
||
}
|
||
handleClose();
|
||
}
|
||
}}
|
||
disabled={hoveredMediaId === null}
|
||
>
|
||
Выбрать
|
||
</Button>
|
||
</DialogActions>
|
||
</Dialog>
|
||
);
|
||
}
|
||
);
|