Created
August 25, 2020 03:23
-
-
Save daviddamilola/2d44ff005978af5921012072a42302b5 to your computer and use it in GitHub Desktop.
custom file upload React component -- draft
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, { useRef } from "react"; | |
import "./FileInput.scss"; | |
import { greyTrash} from "assets/images/svg"; | |
interface InputProps { | |
id?: string; | |
type: string; | |
handleChange?: any; | |
disabled?: boolean; | |
value?: string; | |
placeholder?: string; | |
label?: string; | |
ref?: string; | |
name?: string; | |
textCounter?: number | string; | |
required?: boolean; | |
checked?: boolean; | |
handleBlur?: any; | |
className?: string; | |
message: string; | |
} | |
interface IUploadSuccessProps { | |
thumbnail: any; | |
fileName: any; | |
handleDelete: any; | |
} | |
export const UploadSuccess: React.FunctionComponent<IUploadSuccessProps> = ( | |
{thumbnail, | |
fileName, | |
handleDelete,} | |
) => { | |
return ( | |
<> | |
<div className="input-wrapper thumbnail"> | |
<div className="d-flex w-100 align-items-center justify-content-between "> | |
<span className=" "> | |
<span className=""> | |
<img className="selected-img" src={thumbnail} alt="" /> | |
</span>{" "} | |
<span className="ml-2 fileInput__text">{fileName}</span> | |
</span> | |
<span className="mr-2 delete" onClick={handleDelete}> | |
<img src={greyTrash} alt="delete file" /> | |
</span> | |
</div> | |
<div className="loading w-100"> | |
<div className="progress-p w-50"></div> | |
</div> | |
</div> | |
</> | |
); | |
}; | |
const FileInput: React.SFC<InputProps> = ({ | |
id, | |
message, | |
handleChange, | |
type, | |
disabled, | |
value, | |
placeholder, | |
label, | |
required = false, | |
ref, | |
name, | |
textCounter, | |
checked, | |
handleBlur, | |
className = "", | |
}) => { | |
const fileRef: any = useRef(null); | |
const fakeInputRef: any = useRef(null); | |
const replaceRef: any = useRef(null); | |
const [fileName, setFileName] = React.useState(""); | |
const [thumbnail, setThumbnail]:any = React.useState(null); | |
const handlePaste = (e: any) => { | |
const types = e.dataTransfer.types; | |
if ( | |
!types || | |
(types.contains && types.contains("Files")) || | |
(types.indexOf && types.indexOf("Files") !== -1) | |
) { | |
fileRef.current.classList.add("active"); // Highlight droptarget | |
return false; // We're interested in the drag | |
} | |
}; | |
const awayFromFileTarget = (e: any) => { | |
fileRef.current.classList.remove("active"); | |
}; | |
//referenced from https://gist.github.com/davoclavo/4424731 | |
function dataURItoBlob(dataURI: any) { | |
// convert base64 to raw binary data held in a string | |
var byteString = atob(dataURI.split(',')[1]); | |
// separate out the mime component | |
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; | |
// write the bytes of the string to an ArrayBuffer | |
var arrayBuffer = new ArrayBuffer(byteString.length); | |
var _ia = new Uint8Array(arrayBuffer); | |
for (var i = 0; i < byteString.length; i++) { | |
_ia[i] = byteString.charCodeAt(i); | |
} | |
var dataView = new DataView(arrayBuffer); | |
var blob = new Blob([dataView], { type: mimeString }); | |
return blob; | |
} | |
const getBlobURL = | |
(window.URL && URL.createObjectURL.bind(URL)) || | |
(window.webkitURL && webkitURL.createObjectURL.bind(webkitURL)); | |
const revokeBlobURL = | |
(window.URL && URL.revokeObjectURL.bind(URL)) || | |
(window.webkitURL && webkitURL.revokeObjectURL.bind(webkitURL)); | |
const handleDrop = (e: any) => { | |
e.preventDefault(); | |
const files: any = Array.from(e.dataTransfer.files); | |
const type = files[0].type; | |
if (type.substring(0, 6) !== "video/") return; | |
setFileName(files[0].name); | |
const blobUrl = getBlobURL(files[0]); | |
handleChange(blobUrl); | |
}; | |
const handleInputChange = (e: any) => { | |
setFileName(e.target.value) | |
} | |
const filehandleChange = async (e: any) => { | |
console.log('i was called') | |
let files: any = Array.from(e.target.files); | |
const type = files[0].type; | |
if (type.substring(0, 6) !== "video/") return; | |
setFileName(files[0].name); | |
const blobUrl = getBlobURL(files[0]); | |
//create a video from the video selected or uploaded | |
const video = document.createElement("video"); | |
const canvas: any = document.createElement("canvas"); | |
video.src = blobUrl; | |
video.style.display = "none"; | |
video.preload = "true"; | |
video.width = 150; | |
video.height = 75; | |
let width = 150 | |
let height = 75 | |
canvas.width = width; | |
canvas.height = height; | |
let context = canvas.getContext('2d'); | |
context.drawImage(video, 0, 0, width, height); | |
let dataUri = canvas.toDataURL('image/jpeg'); | |
const imgBlob:any =dataURItoBlob(dataUri); | |
const imgblobUrl: any = getBlobURL(imgBlob) | |
setThumbnail(imgblobUrl); | |
}; | |
const handleDelete:any = () => { | |
revokeBlobURL(thumbnail); | |
setThumbnail(null) | |
setFileName("") | |
} | |
return ( | |
<> | |
{ | |
thumbnail ? <UploadSuccess fileName={fileName} thumbnail={thumbnail} handleDelete={handleDelete} /> : | |
(<label | |
ref={fileRef} | |
htmlFor={id} | |
className="d-flex w-100 align-items-center input-wrapper" | |
> | |
<span className="fileInput__select"> | |
<span ref={replaceRef}>Select file</span> | |
</span> | |
<input | |
onDragEnter={handlePaste} | |
onDragLeave={awayFromFileTarget} | |
onDrop={handleDrop} | |
id="upload" | |
onChange= {handleInputChange} | |
name="upload" | |
value={fileName} | |
className="ml-2 fileInput__text" | |
placeholder={message} | |
ref={fakeInputRef} | |
/> | |
</label> | |
) } | |
<input | |
type="file" | |
name={name} | |
id={id} | |
onChange={filehandleChange} | |
className="fileInput" | |
/> | |
</> | |
); | |
}; | |
export default FileInput; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment