Untitled
unknown
plain_text
a year ago
6.3 kB
4
Indexable
"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;
Editor is loading...
Leave a Comment