Files
WhiteNightsAdminPanel/src/shared/modals/SelectMediaDialog/index.tsx
2025-06-15 20:38:48 +03:00

230 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}
);