Untitled
"use client"; import { HelperText } from "@/components"; import Image from "next/image"; import React, { useCallback, useState, useRef, useEffect } from "react"; import { toast } from "sonner"; interface MediaFile { id: string; file: File; preview: string; } const MediaUpload: React.FC<{ loading: boolean; setSelectedImage: (files: File[]) => void; selectedImage: File[]; name: string; title: string; value: string[]; onChange: (e: { target: { name: string; value: string[] } }) => void; onBlur: (e: { target: { name: string; value: string[] } }) => void; message?: string | string[]; touched?: boolean; }> = ({ name, title, onChange, onBlur, message, touched, // selectedImage, setSelectedImage, loading, value, }) => { const [files, setFiles] = useState<MediaFile[]>([]); const [dragActive, setDragActive] = useState(false); const fileInputRef = useRef<HTMLInputElement>(null); const maxFiles = 3; const maxSize = 5; const handleClick = () => { fileInputRef.current?.click(); }; const handleFiles = useCallback( async (inputFiles: FileList | null) => { if (!inputFiles) return; const newFiles = Array.from(inputFiles).filter((file) => { const isImage = file.type.startsWith("image/"); const sizeInMB = file.size / (1024 * 1024); return isImage && sizeInMB <= maxSize; }); if (files.length + newFiles.length > maxFiles) { toast.message(`Maximum ${maxFiles} files allowed`); return; } // Create preview files for UI const previewFiles = newFiles.map((file) => ({ id: Math.random().toString(36).substring(7), file, preview: URL.createObjectURL(file), })); // Update local state for previews const newFilesList = [...files, ...previewFiles]; setFiles(newFilesList); // Update parent component for Azure upload setSelectedImage(newFiles); // Update form field with existing URLs // Note: The actual URLs will be managed by the parent through imageUrls onChange({ target: { name, value } }); onBlur({ target: { name, value } }); }, [files, name, onChange, onBlur, setSelectedImage, value] ); const handleDrop = useCallback( (e: React.DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); handleFiles(e.dataTransfer.files); }, [handleFiles] ); const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { handleFiles(e.target.files); }; const removeFile = (id: string) => { const fileToRemove = files.find((file) => file.id === id); if (fileToRemove) { URL.revokeObjectURL(fileToRemove.preview); const updatedFiles = files.filter((file) => file.id !== id); setFiles(updatedFiles); // Update parent with remaining files const remainingFiles = updatedFiles.map((file) => file.file); setSelectedImage(remainingFiles); // Update form field onChange({ target: { name, value } }); onBlur({ target: { name, value } }); } }; // Cleanup function to prevent memory leaks useEffect(() => { return () => { files.forEach((file) => { URL.revokeObjectURL(file.preview); }); }; }, [files]); console.log(files,"--files fies") return ( <div className="w-full space-y-4"> <div className="space-y-2"> <p className="border-b border-grey-100 bg-grey-25 px-1 py-2 text-base font-semibold text-gray-900"> {title} </p> <div className="flex flex-wrap gap-4"> {files.map((file) => ( <div key={file.id} className="relative h-48 w-48 overflow-hidden rounded-lg border"> <Image src={file.preview} alt="Product" fill className="h-full w-full object-cover" /> <button type="button" onClick={() => removeFile(file.id)} className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-full bg-red-500 text-white"> × </button> </div> ))} {files.length < maxFiles && ( <div role="button" tabIndex={0} className={`flex h-48 w-48 cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed transition-colors ${ dragActive ? "border-blue-500 bg-blue-50" : "border-grey-300 hover:border-grey-400" }`} onDragOver={(e) => { e.preventDefault(); setDragActive(true); }} onDragLeave={() => setDragActive(false)} onDrop={handleDrop} onClick={handleClick} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); handleClick(); } }}> <svg className="mb-2 h-8 w-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" /> </svg> <span className="text-gray-500"> {dragActive ? "Drop here" : loading ? "Uploading..." : "Tap to upload"} </span> </div> )} </div> <input ref={fileInputRef} type="file" multiple accept="image/*" className="hidden" onChange={handleChange} /> <p className="text-sm text-gray-500"> Maximum of {maxFiles} images ({maxSize}MB) // File format: PNG and JPEG </p> <HelperText touched={touched} message={message} /> </div> </div> ); }; export default MediaUpload;
Leave a Comment