diff --git a/package-lock.json b/package-lock.json index ceaac87..4b4854b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3109,6 +3109,14 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz", "integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", diff --git a/package.json b/package.json index e187fb1..789b9ca 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@testing-library/jest-dom": "^5.11.8", "@testing-library/react": "^11.2.2", "@testing-library/user-event": "^12.6.0", + "axios": "^0.21.1", "material-ui-dropzone": "^3.5.0", "react": "^17.0.1", "react-dom": "^17.0.1", diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx index e9ea0e3..cb97a70 100644 --- a/src/components/FileUploadForm/index.jsx +++ b/src/components/FileUploadForm/index.jsx @@ -1,12 +1,29 @@ -import React from 'react'; -import { Button, Container, CssBaseline, Grid, Typography } from '@material-ui/core'; -import { DropzoneAreaBase } from 'material-ui-dropzone'; -import { useUserContext } from '../Contexts/UserContext'; -import useStyles from '../Styles'; +import React from "react"; +import { Button, Container, CssBaseline, Grid, Typography } from "@material-ui/core"; +import { DropzoneAreaBase } from "material-ui-dropzone"; +import { useUserContext } from "../Contexts/UserContext"; +import { useFileUploadContext, FileUploadProvider } from "../Contexts/FileUploadContext"; +import ModalProgressBar from "../ModalProgressBar"; +import useStyles from "../Styles"; + +const FileUploadZone = ({ classes }) => { + const { uploading, progress, status, upload, cancel } = useFileUploadContext(); + + return ( +
+ + + + ); +}; export default function FileUploadForm() { - const classes = useStyles(); const { signOut } = useUserContext(); + const classes = useStyles(); return ( @@ -15,14 +32,14 @@ export default function FileUploadForm() { Upload file -
- - - - - + + + + + + - +
); diff --git a/src/components/ModalProgressBar/index.jsx b/src/components/ModalProgressBar/index.jsx new file mode 100644 index 0000000..4d79c15 --- /dev/null +++ b/src/components/ModalProgressBar/index.jsx @@ -0,0 +1,44 @@ +import React from "react"; +import Modal from '@material-ui/core/Modal'; + +import { Button, LinearProgress } from "@material-ui/core"; + +const getModalStyle = () => { + const top = 30; + const left = 50; + + return { + width: `350px`, + top: `${top}%`, + left: `${left}%`, + transform: `translate(-${left}%, -${top}%)`, + backgroundColor: `white`, + border: `none`, + position: `absolute`, + margin: `1em`, + padding: `1em`, + textAlign: `center`, + }; +}; + +const ModalProgressBar = ({ onCancel, uploading, progress, status }) => { + const modalStyle = getModalStyle(); + const onClickCancel = () => { + if (onCancel) onCancel(); + } + + return ( + +
+ {status &&

{status}

} + + +
+
+ ); + +} + +export default ModalProgressBar; diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx index f269c39..5b3fc89 100644 --- a/src/components/Routes/SiteRoutes.jsx +++ b/src/components/Routes/SiteRoutes.jsx @@ -21,7 +21,7 @@ const SiteRoutes = () => { } type={TYPES.GUEST} token={token} /> } type={TYPES.GUEST} token={token} /> - } type={TYPES.PROTECTED} token={token} /> + } type={TYPES.PUBLIC} token={token} /> diff --git a/src/components/contexts/FileUploadContext.jsx b/src/components/contexts/FileUploadContext.jsx index 520f2e0..046336a 100644 --- a/src/components/contexts/FileUploadContext.jsx +++ b/src/components/contexts/FileUploadContext.jsx @@ -1,4 +1,5 @@ -import React, { useContext, useEffect, useState } from 'react'; +import React, { useContext, useEffect, useState } from "react"; +import { uploadFile, getCancelToken } from "../../services/uploadFile"; const FileUploadContext = React.createContext(); @@ -6,16 +7,45 @@ export const FileUploadProvider = ({ children }) => { const [file, setFile] = useState(null); const [uploading, setUploading] = useState(false); const [progress, setProgress] = useState(0); + const [status, setStatus] = useState(null); + const [cancelUpload, setCancelUpload] = useState(null); - const upload = (file) => { + const cancel = async () => { + console.log(`cancel`); + if (cancelUpload) cancelUpload.cancel(); + setCancelUpload(null); + setUploading(false); + }; + const upload = async (files) => { + if (files.length === 0) return; + + const file = files[0].file; + const filename = file.name; + + setUploading(true); + setProgress(0); + setStatus(`Uploading ${filename}`); + setCancelUpload(getCancelToken()); + try { + const result = await uploadFile(file, setProgress, cancelUpload); + console.log(result); + setStatus(`Uploaded ${filename}`); + setCancelUpload(null); + setProgress(101); + } + catch (e) { + setStatus(`Error occured ${e.message}`); + } }; return ( {children} diff --git a/src/services/uploadFile.js b/src/services/uploadFile.js new file mode 100644 index 0000000..5f0da86 --- /dev/null +++ b/src/services/uploadFile.js @@ -0,0 +1,29 @@ +import axios from 'axios'; + +const UPLOAD_ENDPOINT = 'http://localhost:8080/api/upload'; + +export const getCancelToken = () => { + const token = axios.CancelToken; + return token.source(); +} + +export const uploadFile = (file, onProgress, cancelToken) => { + const form = new FormData(); + let options = { + method: 'POST', + headers: { + 'Content-Type': 'multipart/form-data', + }, + cancelToken, + }; + if (onProgress) { + options = { + ...options, + onUploadProgress: (event) => { + onProgress(Math.floor((event.loaded / event.total) * 100)); + } + } + } + form.append('file', file); + return axios.post(UPLOAD_ENDPOINT, form, options); +};