File size: 4,118 Bytes
faee5d2 6421be3 faee5d2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
"use client";
import { useCallback, useState, useEffect } from "react";
import { useDropzone } from "react-dropzone";
import { Button } from "./ui/button";
import { Upload as UploadIcon, Image as ImageIcon, X } from "lucide-react";
interface ImageUploadProps {
onImageSelect: (imageData: string) => void;
currentImage: string | null;
}
export function formatFileSize(bytes: number): string {
if (bytes === 0) return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return (
Number.parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]
);
}
export function ImageUpload({ onImageSelect, currentImage }: ImageUploadProps) {
const [selectedFile, setSelectedFile] = useState<File | null>(null);
// Update the selected file when the current image changes
useEffect(() => {
if (!currentImage) {
setSelectedFile(null);
}
}, [currentImage]);
const onDrop = useCallback(
(acceptedFiles: File[]) => {
const file = acceptedFiles[0];
if (!file) return;
setSelectedFile(file);
// Convert the file to base64
const reader = new FileReader();
reader.onload = (event) => {
if (event.target && event.target.result) {
const result = event.target.result as string;
console.log("Image loaded, length:", result.length);
onImageSelect(result);
}
};
reader.onerror = (error) => {
console.error("Error reading file:", error);
};
reader.readAsDataURL(file);
},
[onImageSelect]
);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
"image/png": [".png"],
"image/jpeg": [".jpg", ".jpeg"],
},
maxSize: 10 * 1024 * 1024, // 10MB
multiple: false,
});
const handleRemove = () => {
setSelectedFile(null);
onImageSelect("");
};
return (
<div className="w-full">
{!currentImage ? (
<div
{...getRootProps()}
className={`min-h-[150px] p-4 rounded-lg
${isDragActive ? "bg-secondary/50" : "bg-secondary"}
transition-colors duration-200 ease-in-out hover:bg-secondary/50
border-2 border-dashed border-secondary
cursor-pointer flex items-center justify-center gap-4
`}
>
<input {...getInputProps()} />
<div className="flex flex-row items-center">
<UploadIcon className="w-8 h-8 text-primary mr-3 flex-shrink-0" />
<div className="">
<p className="text-sm font-medium text-foreground">
Drop your image here or click to browse
</p>
<p className="text-xs text-muted-foreground">
Maximum file size: 10MB
</p>
</div>
</div>
</div>
) : (
<div className="flex flex-col items-center p-4 rounded-lg bg-secondary">
<div className="flex w-full items-center mb-4">
<ImageIcon className="w-8 h-8 text-primary mr-3 flex-shrink-0" />
<div className="flex-grow min-w-0">
<p className="text-sm font-medium truncate text-foreground">
{selectedFile?.name || "Current Image"}
</p>
{selectedFile && (
<p className="text-xs text-muted-foreground">
{formatFileSize(selectedFile?.size ?? 0)}
</p>
)}
</div>
<Button
variant="ghost"
size="icon"
onClick={handleRemove}
className="flex-shrink-0 ml-2"
>
<X className="w-4 h-4" />
<span className="sr-only">Remove image</span>
</Button>
</div>
<div className="w-full overflow-hidden rounded-md">
<img
src={currentImage}
alt="Selected"
className="w-full h-auto object-contain"
/>
</div>
</div>
)}
</div>
);
}
|