Created
June 17, 2020 19:17
-
-
Save drewminns/9fa0a1f2c7d2ca6e41bb37af285a4ac3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { RefForwardingComponent, useReducer, useState, useEffect, forwardRef, useImperativeHandle } from 'react' | |
import ImageKit from 'imagekit-javascript' | |
import { ImageKitResponse } from '../interfaces' | |
const imagekit = new ImageKit({ | |
publicKey: process.env.IMAGEKIT_PUBLIC_KEY || 'fasdf', | |
urlEndpoint: process.env.IMAGEKIT_ENDPOINT || 'asdfasdf', | |
authenticationEndpoint: '/api/auth/assets', | |
}) | |
export interface ImageUploadRefMethods { | |
uploadImageKitService: () => Promise<ImageKitResponse[]> | |
} | |
interface ImageUploadProps { | |
onUpdate: (response: File[]) => any | |
ref: any | |
} | |
const initialState: File[] = [] | |
const imageListReducer = (state: File[], action: { type: string; payload?: any }) => { | |
switch (action.type) { | |
case 'add': | |
const data = [...state, ...action.payload] | |
return Array.from(new Set(data)) | |
case 'remove': | |
return state.filter((file: File) => file.name !== action.payload) | |
case 'clear': | |
return initialState | |
default: | |
throw new Error() | |
} | |
} | |
const ImageUploadComponent: React.RefForwardingComponent<ImageUploadRefMethods, ImageUploadProps> = ( | |
{ onUpdate }, | |
ref, | |
) => { | |
const [fileList, dispatch] = useReducer(imageListReducer, initialState) | |
const [isDraggedOver, updatedDragStatus] = useState<boolean>(false) | |
useEffect(() => { | |
onUpdate(fileList) | |
}, [fileList]) | |
useImperativeHandle(ref, () => ({ | |
async uploadImageKitService(): Promise<ImageKitResponse[]> { | |
try { | |
const uploadGroup = fileList.map( | |
(file: File) => | |
new Promise((resolve) => | |
imagekit.upload({ file, fileName: file.name }, (err: any, result: ImageKitResponse) => resolve(result)), | |
), | |
) | |
const result = await Promise.all(uploadGroup) | |
dispatch({ type: 'clear' }) | |
return result as ImageKitResponse[] | |
} catch (err) { | |
throw new Error() | |
} | |
}, | |
})) | |
function addFilesOnDrop(evt: React.DragEvent<HTMLDivElement>): void { | |
evt.preventDefault() | |
evt.stopPropagation() | |
updatedDragStatus(false) | |
dispatch({ type: 'add', payload: evt.dataTransfer.files }) | |
onUpdate(fileList) | |
} | |
function addFilesInput(evt: React.ChangeEvent<HTMLInputElement>): void { | |
evt.preventDefault() | |
evt.stopPropagation() | |
dispatch({ type: 'add', payload: evt.target.files }) | |
onUpdate(fileList) | |
} | |
function trackDrag(event: Event | React.DragEvent<HTMLDivElement>, status: boolean): void { | |
event.stopPropagation() | |
event.preventDefault() | |
updatedDragStatus(status) | |
} | |
return ( | |
<div> | |
<div | |
style={{ height: '300px', borderWidth: isDraggedOver ? '2px' : '1px', borderColor: '#000' }} | |
onDrop={addFilesOnDrop} | |
onDragOver={(e) => trackDrag(e, true)} | |
onDragLeave={(e) => trackDrag(e, false)} | |
> | |
<p> | |
<label htmlFor="file">Choose Images</label> or drop them here | |
</p> | |
<ul style={{ display: 'flex' }}> | |
{fileList.map((file: File) => ( | |
<li key={file.name + file.size} style={{ width: '150px', position: 'relative' }}> | |
<img style={{ maxWidth: '100%' }} src={URL.createObjectURL(file)} alt={file.name} /> | |
<button onClick={() => dispatch({ type: 'remove', payload: file.name })}>Remove</button> | |
</li> | |
))} | |
</ul> | |
</div> | |
<input type="file" style={{ display: 'none' }} multiple id="file" onChange={addFilesInput} /> | |
</div> | |
) | |
} | |
ImageUploadComponent.displayName = 'Image Upload' | |
export const ImageUpload = forwardRef(ImageUploadComponent) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment