diff --git a/package.json b/package.json index 89e2ce19..635371a2 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "ramda": "^0.26.1", "react": "^16.9.0", "react-dom": "^16.9.0", + "react-dropzone": "^10.1.8", "react-router-dom": "^5.0.1", "react-scripts": "3.1.1", "react-virtualized": "^9.21.1", diff --git a/src/firebase/index.ts b/src/firebase/index.ts index cc67816e..75601f09 100644 --- a/src/firebase/index.ts +++ b/src/firebase/index.ts @@ -2,6 +2,7 @@ import firebase from "firebase/app"; import "firebase/auth"; import "firebase/firestore"; import "firebase/functions"; +import "firebase/storage"; import { productionConfig, stagingConfig } from "./config"; @@ -15,5 +16,6 @@ if (process.env.REACT_APP_ENV === "PRODUCTION") { export const auth = firebase.auth(); export const db = firebase.firestore(); +export const bucket = firebase.storage(); export const functions = firebase.app().functions(); export const googleProvider = new firebase.auth.GoogleAuthProvider(); diff --git a/src/hooks/useFiretable/useUploader.ts b/src/hooks/useFiretable/useUploader.ts index aeedafd4..48e0c83b 100644 --- a/src/hooks/useFiretable/useUploader.ts +++ b/src/hooks/useFiretable/useUploader.ts @@ -1,6 +1,68 @@ -import { useState } from "react"; +import { useReducer } from "react"; +import { bucket } from "../../firebase/index"; -const useUploader = () => { - // const - // return [uploaderState,] +import firebase, { FirebaseError } from "firebase/app"; +const intialState = {}; +const uploadReducer = (prevState: any, newProps: any) => { + return { ...prevState, ...newProps }; }; +const useUploader = (collectionPath: string) => { + const [uploaderState, uploaderDispatch] = useReducer(uploadReducer, { + ...intialState, + collectionPath + }); + const setCollectionPath = (path: string) => { + var collectionPath = bucket.ref(path); + uploaderDispatch({ collectionPath }); + }; + const upload = (docId: string, fieldName: string, file: File) => { + const storageRef = uploaderState.storagePath.child( + `${docId}/${fieldName}/${file.name}.${file.type}` + ); + var uploadTask = storageRef.put(file); + uploadTask.on( + firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed' + function(snapshot: any) { + // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded + var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log("Upload is " + progress + "% done"); + switch (snapshot.state) { + case firebase.storage.TaskState.PAUSED: // or 'paused' + console.log("Upload is paused"); + break; + case firebase.storage.TaskState.RUNNING: // or 'running' + console.log("Upload is running"); + break; + } + }, + function(error: FirebaseError) { + // A full list of error codes is available at + // https://firebase.google.com/docs/storage/web/handle-errors + switch (error.code) { + case "storage/unauthorized": + // User doesn't have permission to access the object + break; + + case "storage/canceled": + // User canceled the upload + break; + case "storage/unknown": + // Unknown error occurred, inspect error.serverResponse + break; + } + }, + function() { + // Upload completed successfully, now we can get the download URL + uploadTask.snapshot.ref + .getDownloadURL() + .then(function(downloadURL: string) { + console.log("File available at", downloadURL); + }); + } + ); + }; + const uploadActions = { upload, setCollectionPath }; + return [uploaderState, uploadActions]; +}; + +export default useUploader; diff --git a/yarn.lock b/yarn.lock index a01a16c5..34745649 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2296,6 +2296,13 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +attr-accept@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52" + integrity sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ== + dependencies: + core-js "^2.5.0" + autoprefixer@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" @@ -3265,7 +3272,7 @@ core-js@^1.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= -core-js@^2.4.0: +core-js@^2.4.0, core-js@^2.5.0: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -4606,6 +4613,13 @@ file-loader@3.0.1: loader-utils "^1.0.2" schema-utils "^1.0.0" +file-selector@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.12.tgz#fe726547be219a787a9dcc640575a04a032b1fd0" + integrity sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ== + dependencies: + tslib "^1.9.0" + filesize@3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" @@ -8949,6 +8963,15 @@ react-dom@^16.9.0: prop-types "^15.6.2" scheduler "^0.15.0" +react-dropzone@^10.1.8: + version "10.1.8" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-10.1.8.tgz#348895a3ee9efe7c0f6a2f19642f04704c170757" + integrity sha512-Lm6+TxIDf/my4i3VdYmufRcrJ4SUbSTJP3HB49V2+HNjZwLI4NKVkaNRHwwSm9CEuzMP+6SW7pT1txc1uBPfDg== + dependencies: + attr-accept "^1.1.3" + file-selector "^0.1.11" + prop-types "^15.7.2" + react-error-overlay@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f"