import { Box, Stack, Typography, IconButton } from "@mui/material"; import { useTheme } from "@mui/material/styles"; import { Upload, X } from "lucide-react"; import { useState, useRef, useCallback } from "react"; import { useTranslation } from "react-i18next"; interface FileObject { src: string; name: string; file: File; } interface ImageUploadProps { src?: string; onChange?: (file: FileObject | undefined) => void; maxSize?: number; accept?: string[]; error?: string; } export const ImageUpload = ({ src, onChange, maxSize = 3 * 1024 * 1024, accept = ["jpg", "jpeg", "png"], error, }: ImageUploadProps) => { const theme = useTheme(); const { t } = useTranslation(); const inputRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const [localError, setLocalError] = useState(null); const [preview, setPreview] = useState(null); const handleFile = useCallback( (file: File | undefined) => { if (!file) return; const isValidType = accept.some((type) => file.type.includes(type)); const isValidSize = file.size <= maxSize; if (!isValidType) { setLocalError(t("components.imageUpload.errors.invalidFileFormat")); return; } if (!isValidSize) { setLocalError(t("components.imageUpload.errors.invalidFileSize")); return; } setLocalError(null); const fileObj: FileObject = { src: URL.createObjectURL(file), name: file.name, file, }; setPreview(fileObj); onChange?.(fileObj); }, [maxSize, accept, onChange, t] ); const handleClear = () => { setPreview(null); setLocalError(null); onChange?.(undefined); if (inputRef.current) inputRef.current.value = ""; }; const displaySrc = src || preview?.src; const displayError = localError || error; return ( {displaySrc ? ( ) : ( { e.preventDefault(); setIsDragging(true); }} onDragLeave={() => setIsDragging(false)} onDrop={(e) => { e.preventDefault(); setIsDragging(false); handleFile(e.dataTransfer.files?.[0]); }} alignItems="center" justifyContent="center" gap={1} sx={{ position: "relative", width: "100%", minHeight: 150, border: "2px dashed", borderRadius: 1, borderColor: isDragging ? theme.palette.primary.main : theme.palette.divider, backgroundColor: isDragging ? theme.palette.action.hover : "transparent", transition: "0.2s", cursor: "pointer", "&:hover": { borderColor: theme.palette.primary.main, backgroundColor: theme.palette.action.hover, }, }} > `.${ext}`).join(",")} onChange={(e) => handleFile(e.target.files?.[0])} style={{ position: "absolute", inset: 0, opacity: 0, cursor: "pointer" }} /> {t("components.imageUpload.clickToUpload")} {" "} {t("components.imageUpload.orDragAndDrop")} {accept.join(", ").toUpperCase()} • {t("components.imageUpload.maxSize")}{" "} {Math.round(maxSize / 1024 / 1024)}MB )} {displayError && ( {displayError} )} ); };