Wire up file upload form

This commit is contained in:
jwu-fisker
2021-01-07 14:10:58 -08:00
parent 8fc6b3b6d8
commit 0ae42bf51d
7 changed files with 145 additions and 16 deletions

8
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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 (
<form className={classes.form} noValidate>
<DropzoneAreaBase
maxFileSize={5e+7}
showAlerts={false}
onAdd={upload}
/>
<ModalProgressBar uploading={uploading} progress={progress} onCancel={cancel} status={status} />
</form>
);
};
export default function FileUploadForm() {
const classes = useStyles();
const { signOut } = useUserContext();
const classes = useStyles();
return (
<Container component="main" maxWidth="xs">
@@ -15,14 +32,14 @@ export default function FileUploadForm() {
<Typography component="h1" variant="h5">
Upload file
</Typography>
<form className={classes.form} noValidate>
<DropzoneAreaBase />
<FileUploadProvider>
<FileUploadZone classes={classes} />
</FileUploadProvider>
<Grid container>
<Grid item >
<Button onClick={signOut}>Sign Out</Button>
</Grid>
</Grid>
</form>
</div>
</Container>
);

View File

@@ -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 (
<Modal open={uploading}>
<div style={modalStyle}>
{status && <p>{status}</p>}
<LinearProgress variant="determinate" value={progress} />
<Button onClick={onClickCancel}>
{ progress < 101 ? "Cancel" : "Done" }
</Button>
</div>
</Modal>
);
}
export default ModalProgressBar;

View File

@@ -21,7 +21,7 @@ const SiteRoutes = () => {
<Switch>
<AuthRoute path="/" exact render={() => <SignInForm />} type={TYPES.GUEST} token={token} />
<AuthRoute path="/signup" exact render={() => <SignUpForm />} type={TYPES.GUEST} token={token} />
<AuthRoute path="/home" render={() => <FileUploadForm />} type={TYPES.PROTECTED} token={token} />
<AuthRoute path="/home" render={() => <FileUploadForm />} type={TYPES.PUBLIC} token={token} />
</Switch>
</BrowserRouter>
</Suspense>

View File

@@ -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 (
<FileUploadContext.Provider value={{
uploading,
progress,
status,
upload,
cancel,
}}>
{children}
</FileUploadContext.Provider>

View File

@@ -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);
};