"use client"; import React, { useEffect, useMemo, useState } from "react"; import Image from "next/image"; import clsx from "clsx"; import { UploadCloud, X } from "lucide-react"; import { toastError, toastWarn } from "@/common/funcs/toast"; import { UploadImageProps } from "./interface"; const MAXIMUM_FILE = 10; // MB const ACCEPT_TYPES = ["image/jpeg", "image/jpg", "image/png"]; /* ========================= COMPONENT ========================= */ const UploadImage = ({ label, name, path, file, setFile, resetPath, isWidthFull = true, disabled = false, }: UploadImageProps) => { const [dragging, setDragging] = useState(false); /* ========================= PREVIEW IMAGE ========================= */ const imagePreview = useMemo(() => { if (!file) return ""; return URL.createObjectURL(file); }, [file]); /* ========================= CLEANUP OBJECT URL ========================= */ useEffect(() => { return () => { if (imagePreview) { URL.revokeObjectURL(imagePreview); } }; }, [imagePreview]); /* ========================= VALIDATE FILE ========================= */ const validateFile = (selectedFile: File | null | undefined) => { if (!selectedFile) return; const { size, type } = selectedFile; /** * CHECK SIZE */ if (size / 1000000 > MAXIMUM_FILE) { return toastError({ msg: `Kích thước tối đa của ảnh là ${MAXIMUM_FILE} MB`, }); } /** * CHECK TYPE */ if (!ACCEPT_TYPES.includes(type)) { return toastWarn({ msg: "Định dạng không hợp lệ. Chỉ chấp nhận JPG, JPEG, PNG", }); } /** * SET FILE */ setFile(selectedFile); }; /* ========================= DRAG EVENTS ========================= */ const handleDragEnter = (e: React.DragEvent): void => { e.preventDefault(); if (disabled) return; setDragging(true); }; const handleDragLeave = (): void => { setDragging(false); }; const handleDrop = (e: React.DragEvent): void => { e.preventDefault(); if (disabled) return; setDragging(false); const droppedFile = e.dataTransfer.files?.[0]; validateFile(droppedFile); }; /* ========================= SELECT FILE ========================= */ const handleSelectImage = (e: React.ChangeEvent): void => { if (disabled) return; const selectedFile = e.target.files?.[0]; validateFile(selectedFile); }; /* ========================= REMOVE IMAGE ========================= */ const handleRemoveImage = (): void => { setFile(null); resetPath?.(); }; /* ========================= IMAGE SOURCE ========================= */ const imageSrc = imagePreview || path || ""; /* ========================= UI ========================= */ return (
{/* LABEL */} {label && (
{typeof label === "string" ? (

{label}

) : ( label )}
)} {/* PREVIEW */} {imageSrc ? (
Preview image {/* REMOVE BUTTON */} {!disabled && ( )}
) : ( )}
); }; export default UploadImage;