import React, { useState, ChangeEvent, DragEvent, useRef, useEffect } from 'react' import { observer } from 'mobx-react' import { KeenSliderInstance, useKeenSlider } from 'keen-slider/react' import 'keen-slider/keen-slider.min.css' import './styles.css' import { FormStoreType, FormFields } from '../../../store' import { MemoryBlockStore } from 'ipfs-car/blockstore/memory' import { packToBlob } from 'ipfs-car/pack/blob' import { NFTStorage } from 'nft.storage' import { KeenSliderHooks, TrackDetails } from 'keen-slider' interface ImageUploadProps { name: keyof T formStore: FormStoreType } const ImageUpload = observer( ({ name, formStore }: ImageUploadProps) => { const client = new NFTStorage({ token: process.env.NEXT_PUBLIC_NFT_STORAGE_TOKEN || '', }) const acceptableMIME = [ 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp', 'image/gif', ] const [uploadArtworkError, setUploadArtworkError] = useState() const [previews, setPreviews] = useState([]) const [isUploading, setIsUploading] = useState(false) const [slider, setSlider] = useState | null>(null) // Reinitialize slider when new images are added useEffect(() => { if (slider && previews.length) { slider.update() } }, [previews, slider]) const [sliderRef, sliderInstance] = useKeenSlider({ loop: false, mode: 'free-snap', slides: { perView: 1.5, spacing: 10, }, created(s) { setSlider(s) }, }) useEffect(() => { const initialImages = formStore.fields[name] as string[] if (initialImages && initialImages.length) { const previewUrls = initialImages.map( (uri) => `https://ipfs.io/ipfs/${uri.split('ipfs://')[1]}`, ) setPreviews(previewUrls) } }, [formStore.fields, name]) const fileInputRef = useRef(null) const handleClickUploadArea = () => { fileInputRef.current?.click() } const handleFileUpload = async ( event: ChangeEvent | DragEvent, ) => { let files: File[] if (event.type === 'drop') { files = Array.from((event as DragEvent).dataTransfer.files) } else { files = Array.from((event as ChangeEvent).target.files || []) } if (!files.length) return const unsupportedFile = files.find((file) => !acceptableMIME.includes(file.type)) if (unsupportedFile) { setUploadArtworkError({ mime: `${unsupportedFile.type} is an unsupported file type`, }) return } setIsUploading(true) setUploadArtworkError(null) try { let existingURIs = (formStore.fields[name] as string[]) || [] let newImageURIs = [...existingURIs] for (const file of files) { const car = await packToBlob({ input: [{ content: file, path: file.name }], blockstore: new MemoryBlockStore(), }) const cid = await client.storeCar(car.car) const uri = `ipfs://${cid}/${encodeURIComponent(file.name)}` const previewUrl = `https://ipfs.io/ipfs/${cid}/${encodeURIComponent(file.name)}` newImageURIs.push(uri) setPreviews((prev) => [...prev, previewUrl]) } formStore.setField(name as keyof T, newImageURIs as T[keyof T]) setIsUploading(false) } catch (err) { setIsUploading(false) setUploadArtworkError(err) } } const handleDragOver = (e: DragEvent) => e.preventDefault() const handleDrop = (e: DragEvent) => { e.preventDefault() handleFileUpload(e) } return (
{isUploading ? 'Uploading...' : 'Drag and drop files here or click to upload'}
{previews.map((src, idx) => (
))}
{uploadArtworkError?.mime && (
  • {uploadArtworkError.mime}
)}
) }, ) export default ImageUpload