165 lines
4.5 KiB
TypeScript
165 lines
4.5 KiB
TypeScript
import { Box, ButtonBase, IconButton, Typography, useTheme } from "@mui/material";
|
||
import { useState, useRef, useEffect } from "react";
|
||
import CloseIcon from "@mui/icons-material/Close";
|
||
|
||
type OwnImageProps = {
|
||
imageUrl?: string;
|
||
};
|
||
|
||
export const OwnImage = ({ imageUrl }: OwnImageProps) => {
|
||
const theme = useTheme();
|
||
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
||
const [isDropzoneHighlighted, setIsDropzoneHighlighted] = useState(false);
|
||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||
|
||
// Sync state if external imageUrl changes
|
||
useEffect(() => {
|
||
if (imageUrl) {
|
||
setSelectedFile(null); // Clear local file selection when external URL is provided
|
||
}
|
||
}, [imageUrl]);
|
||
|
||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||
const file = event.target.files?.[0];
|
||
if (file && file.type.startsWith("image/")) {
|
||
setSelectedFile(file);
|
||
}
|
||
};
|
||
|
||
const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
setIsDropzoneHighlighted(false);
|
||
const file = event.dataTransfer.files?.[0];
|
||
if (file && file.type.startsWith("image/")) {
|
||
setSelectedFile(file);
|
||
}
|
||
};
|
||
|
||
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
};
|
||
|
||
const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
setIsDropzoneHighlighted(true);
|
||
};
|
||
|
||
const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
|
||
event.preventDefault();
|
||
event.stopPropagation();
|
||
setIsDropzoneHighlighted(false);
|
||
};
|
||
|
||
const handleClick = (e: React.MouseEvent) => {
|
||
e.stopPropagation();
|
||
if (fileInputRef.current) {
|
||
fileInputRef.current.value = "";
|
||
}
|
||
fileInputRef.current?.click();
|
||
};
|
||
|
||
const handleRemoveImage = (e: React.MouseEvent) => {
|
||
e.stopPropagation();
|
||
setSelectedFile(null);
|
||
};
|
||
|
||
const imageToDisplay = selectedFile ? URL.createObjectURL(selectedFile) : imageUrl;
|
||
|
||
return (
|
||
<ButtonBase
|
||
component="div"
|
||
onClick={handleClick}
|
||
onDrop={handleDrop}
|
||
onDragOver={handleDragOver}
|
||
onDragEnter={handleDragEnter}
|
||
onDragLeave={handleDragLeave}
|
||
sx={{
|
||
width: "100%",
|
||
height: "100%",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
borderRadius: "12px",
|
||
transition: "border-color 0.3s, background-color 0.3s",
|
||
overflow: "hidden",
|
||
position: "relative",
|
||
"&:hover .overlay": {
|
||
opacity: 1,
|
||
},
|
||
}}
|
||
>
|
||
<input
|
||
type="file"
|
||
ref={fileInputRef}
|
||
onChange={handleFileChange}
|
||
accept="image/*"
|
||
hidden
|
||
/>
|
||
{imageToDisplay ? (
|
||
<>
|
||
<Box sx={{ width: "100%", height: "100%", position: "relative" }}>
|
||
<img
|
||
src={imageToDisplay}
|
||
alt="Preview"
|
||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||
/>
|
||
</Box>
|
||
<Box
|
||
className="overlay"
|
||
sx={{
|
||
position: "absolute",
|
||
top: 0,
|
||
left: 0,
|
||
width: "100%",
|
||
height: "100%",
|
||
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
||
opacity: 0,
|
||
transition: "opacity 0.3s",
|
||
pointerEvents: "none",
|
||
}}
|
||
/>
|
||
{selectedFile && (
|
||
<IconButton
|
||
onClick={handleRemoveImage}
|
||
sx={{
|
||
position: "absolute",
|
||
top: 8,
|
||
right: 8,
|
||
zIndex: 1,
|
||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||
color: "white",
|
||
"&:hover": {
|
||
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
||
},
|
||
}}
|
||
>
|
||
<CloseIcon />
|
||
</IconButton>
|
||
)}
|
||
</>
|
||
) : (
|
||
<Box
|
||
sx={{
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
opacity: 0.5,
|
||
}}
|
||
>
|
||
<Typography
|
||
variant="body2"
|
||
color="text.secondary"
|
||
sx={{ p: 2, textAlign: "center" }}
|
||
>
|
||
добавьте свою картинку
|
||
</Typography>
|
||
</Box>
|
||
)}
|
||
</ButtonBase>
|
||
);
|
||
};
|