From c3229c4d5532b8806a3950bb20e46667545b0196 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 11:28:10 -0800 Subject: [PATCH 01/64] Add sign in, sign up, and upload forms --- .eslintcache | 2 +- package-lock.json | 131 ++++++++++++++++++++++++ package.json | 3 + public/favicon.ico | Bin 3870 -> 1150 bytes public/index.html | 27 +---- public/logo-192.png | Bin 0 -> 39505 bytes public/logo-512.png | Bin 0 -> 122784 bytes public/logo192.png | Bin 5347 -> 0 bytes public/logo512.png | Bin 9664 -> 0 bytes src/components/App/index.js | 40 +++++--- src/components/FileUploadForm/index.jsx | 30 ++++++ src/components/SignInForm/index.jsx | 63 ++++++++++++ src/components/SignUpForm/index.jsx | 73 +++++++++++++ src/components/Styles.jsx | 23 +++++ src/index.js | 6 +- 15 files changed, 354 insertions(+), 44 deletions(-) create mode 100644 public/logo-192.png create mode 100644 public/logo-512.png delete mode 100644 public/logo192.png delete mode 100644 public/logo512.png create mode 100644 src/components/FileUploadForm/index.jsx create mode 100644 src/components/SignUpForm/index.jsx create mode 100644 src/components/Styles.jsx diff --git a/.eslintcache b/.eslintcache index 79c070b..41a0b2b 100644 --- a/.eslintcache +++ b/.eslintcache @@ -1 +1 @@ -[{"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js":"1","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js":"2","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx":"3","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js":"4"},{"size":610,"mtime":1609866784202,"results":"5","hashOfConfig":"6"},{"size":362,"mtime":1609865788231,"results":"7","hashOfConfig":"6"},{"size":682,"mtime":1609866806365,"results":"8","hashOfConfig":"6"},{"size":406,"mtime":1609866869723,"results":"9","hashOfConfig":"6"},{"filePath":"10","messages":"11","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1qss98p",{"filePath":"12","messages":"13","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14","messages":"15","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16","messages":"17","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js",[]] \ No newline at end of file +[{"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js":"1","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js":"2","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx":"3","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js":"4","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignInForm/index.jsx":"5","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/Styles.jsx":"6","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignUpForm/index.jsx":"7","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/FileUploadForm/index.jsx":"8"},{"size":570,"mtime":1609873441348,"results":"9","hashOfConfig":"10"},{"size":362,"mtime":1609865788231,"results":"11","hashOfConfig":"10"},{"size":682,"mtime":1609866806365,"results":"12","hashOfConfig":"10"},{"size":764,"mtime":1609873518945,"results":"13","hashOfConfig":"10"},{"size":1895,"mtime":1609872149128,"results":"14","hashOfConfig":"10"},{"size":491,"mtime":1609871500052,"results":"15","hashOfConfig":"10"},{"size":2181,"mtime":1609872178277,"results":"16","hashOfConfig":"10"},{"size":932,"mtime":1609874852016,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1qss98p",{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"24","messages":"25","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"28"},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"28"},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignInForm/index.jsx",[],["35","36"],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/Styles.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignUpForm/index.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/FileUploadForm/index.jsx",[],{"ruleId":"37","replacedBy":"38"},{"ruleId":"39","replacedBy":"40"},"no-native-reassign",["41"],"no-negated-in-lhs",["42"],"no-global-assign","no-unsafe-negation"] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 61ce7d9..4b6b58e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1764,6 +1764,14 @@ "react-transition-group": "^4.4.0" } }, + "@material-ui/icons": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", + "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", + "requires": { + "@babel/runtime": "^7.4.4" + } + }, "@material-ui/styles": { "version": "4.11.2", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.2.tgz", @@ -3067,6 +3075,11 @@ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, + "attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" + }, "autoprefixer": { "version": "9.8.6", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", @@ -6501,6 +6514,21 @@ } } }, + "file-selector": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.19.tgz", + "integrity": "sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==", + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -7140,6 +7168,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -9987,6 +10028,16 @@ "object-visit": "^1.0.0" } }, + "material-ui-dropzone": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/material-ui-dropzone/-/material-ui-dropzone-3.5.0.tgz", + "integrity": "sha512-3BC6mz/4OEM4ZpbqMfuMN065JQyqfEbifT6/VzIua7Zj4b0DaR5YPCgpN+fL/e8yBgTs9MGBZJQY06p5pfKwvw==", + "requires": { + "@babel/runtime": "^7.4.4", + "clsx": "^1.0.2", + "react-dropzone": "^10.2.1" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -10118,6 +10169,15 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, "mini-css-extract-plugin": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz", @@ -12541,6 +12601,16 @@ "scheduler": "^0.20.1" } }, + "react-dropzone": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-10.2.2.tgz", + "integrity": "sha512-U5EKckXVt6IrEyhMMsgmHQiWTGLudhajPPG77KFSvgsMqNEHSyGpqWvOMc5+DhEah/vH4E1n+J5weBNLd5VtyA==", + "requires": { + "attr-accept": "^2.0.0", + "file-selector": "^0.1.12", + "prop-types": "^15.7.2" + } + }, "react-error-overlay": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz", @@ -12556,6 +12626,52 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "react-scripts": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.1.tgz", @@ -13023,6 +13139,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -14702,6 +14823,11 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, "tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -15177,6 +15303,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 651a2d3..5c2a112 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,14 @@ "private": true, "dependencies": { "@material-ui/core": "^4.11.2", + "@material-ui/icons": "^4.11.2", "@testing-library/jest-dom": "^5.11.8", "@testing-library/react": "^11.2.2", "@testing-library/user-event": "^12.6.0", + "material-ui-dropzone": "^3.5.0", "react": "^17.0.1", "react-dom": "^17.0.1", + "react-router-dom": "^5.2.0", "react-scripts": "4.0.1", "web-vitals": "^0.2.4" }, diff --git a/public/favicon.ico b/public/favicon.ico index a11777cc471a4344702741ab1c8a588998b1311a..bd53ce5a1ecdbfccfe95aa4d38b748951c2d2b29 100644 GIT binary patch literal 1150 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ diff --git a/public/index.html b/public/index.html index aa069f2..d3d4b18 100644 --- a/public/index.html +++ b/public/index.html @@ -10,34 +10,13 @@ content="Web site created using create-react-app" /> - - - React App + + + File Upload App
- diff --git a/public/logo-192.png b/public/logo-192.png new file mode 100644 index 0000000000000000000000000000000000000000..89a7f7d3bb9bdc572588624ea1ec13a5af314903 GIT binary patch literal 39505 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
B0hE-K=z;BzrcRwY`i`TI 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 FV1fu<(%Aq2 literal 0 HcmV?d00001 diff --git a/public/logo-512.png b/public/logo-512.png new file mode 100644 index 0000000000000000000000000000000000000000..302133bdc05b7853be962fd1b71510d55f500141 GIT binary patch literal 122784 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

LCzpP{-sbf2dA_M#>tqljXdOq2uzfcU^UXaDT} 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Ĩ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%0ArfLR_ObkK-@oE_|AFT|=RWtG^Ljt;_j%vZMr6L_ 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 b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN diff --git a/src/components/App/index.js b/src/components/App/index.js index 8e7c207..b324cd8 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -1,22 +1,32 @@ +import React, { Suspense } from 'react'; +import { + BrowserRouter, + Switch, + Route +} from 'react-router-dom'; import './App.css'; +const SignInForm = React.lazy(() => import('../SignInForm')); +const SignUpForm = React.lazy(() => import('../SignUpForm')); +const FileUploadForm = React.lazy(() => import('../FileUploadForm')); + function App() { return ( -

+ + + + + + + + + + + + + + + ); } diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx new file mode 100644 index 0000000..de0d637 --- /dev/null +++ b/src/components/FileUploadForm/index.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Link as RouterLink } from 'react-router-dom'; +import { Container, CssBaseline, Grid, Link, Typography } from '@material-ui/core'; +import { DropzoneAreaBase } from 'material-ui-dropzone'; +import useStyles from '../Styles'; + +export default function FileUploadForm() { + const classes = useStyles(); + + return ( + + +
+ + Upload File + +
+ + + + + {"Sign Out"} + + + + +
+
+ ); + } \ No newline at end of file diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index e69de29..36320e6 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { Link as RouterLink } from 'react-router-dom'; +import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; +import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; +import useStyles from '../Styles'; + +export default function SignInForm() { + const classes = useStyles(); + + return ( + + +
+ + + + + Sign in + +
+ + + + + + + {"Don't have an account? Sign Up"} + + + + +
+
+ ); + } \ No newline at end of file diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx new file mode 100644 index 0000000..da0e403 --- /dev/null +++ b/src/components/SignUpForm/index.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Link as RouterLink } from 'react-router-dom'; +import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; +import LockOpenOutlinedIcon from '@material-ui/icons/LockOpenOutlined'; +import useStyles from '../Styles'; + +export default function SignInForm() { + const classes = useStyles(); + + return ( + + +
+ + + + + Sign in + +
+ + + + + + + + {"Already have an account? Sign In"} + + + + +
+
+ ); + } \ No newline at end of file diff --git a/src/components/Styles.jsx b/src/components/Styles.jsx new file mode 100644 index 0000000..d2beb00 --- /dev/null +++ b/src/components/Styles.jsx @@ -0,0 +1,23 @@ +import { makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles((theme) => ({ + paper: { + marginTop: theme.spacing(8), + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + }, + avatar: { + margin: theme.spacing(1), + backgroundColor: theme.palette.primary.main, + }, + form: { + width: '100%', // Fix IE 11 issue. + marginTop: theme.spacing(1), + }, + submit: { + margin: theme.spacing(3, 0, 2), + }, +})); + +export default useStyles; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 3e3fa7f..29ba346 100644 --- a/src/index.js +++ b/src/index.js @@ -2,14 +2,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './components/App'; -import ErrorBoundary from './components/ErrorBoundary'; +// import ErrorBoundary from './components/ErrorBoundary'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( - - - + , document.getElementById('root') ); From 84962ec16ccf8280570809a15ade979986addc7e Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 11:35:08 -0800 Subject: [PATCH 02/64] Do not check in .eslintcache --- .eslintcache | 1 - .gitignore | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 .eslintcache diff --git a/.eslintcache b/.eslintcache deleted file mode 100644 index 41a0b2b..0000000 --- a/.eslintcache +++ /dev/null @@ -1 +0,0 @@ -[{"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js":"1","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js":"2","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx":"3","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js":"4","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignInForm/index.jsx":"5","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/Styles.jsx":"6","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignUpForm/index.jsx":"7","/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/FileUploadForm/index.jsx":"8"},{"size":570,"mtime":1609873441348,"results":"9","hashOfConfig":"10"},{"size":362,"mtime":1609865788231,"results":"11","hashOfConfig":"10"},{"size":682,"mtime":1609866806365,"results":"12","hashOfConfig":"10"},{"size":764,"mtime":1609873518945,"results":"13","hashOfConfig":"10"},{"size":1895,"mtime":1609872149128,"results":"14","hashOfConfig":"10"},{"size":491,"mtime":1609871500052,"results":"15","hashOfConfig":"10"},{"size":2181,"mtime":1609872178277,"results":"16","hashOfConfig":"10"},{"size":932,"mtime":1609874852016,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1qss98p",{"filePath":"20","messages":"21","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"24","messages":"25","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"28"},{"filePath":"29","messages":"30","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"31","messages":"32","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"28"},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/index.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/reportWebVitals.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/ErrorBoundary.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/App/index.js",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignInForm/index.jsx",[],["35","36"],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/Styles.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/SignUpForm/index.jsx",[],"/Users/jwufiskerinc.com/Documents/GitHub/file-upload-webapp/src/components/FileUploadForm/index.jsx",[],{"ruleId":"37","replacedBy":"38"},{"ruleId":"39","replacedBy":"40"},"no-native-reassign",["41"],"no-negated-in-lhs",["42"],"no-global-assign","no-unsafe-negation"] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4d29575..00ec607 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ .env.development.local .env.test.local .env.production.local +.eslintcache npm-debug.log* yarn-debug.log* From cbb0c682d37e78f48789d1bf71b561c5680bc77a Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 11:35:34 -0800 Subject: [PATCH 03/64] Correct text lablels --- src/components/SignInForm/index.jsx | 2 +- src/components/SignUpForm/index.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index 36320e6..fd7424e 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -47,7 +47,7 @@ export default function SignInForm() { color="primary" className={classes.submit} > - Sign Up + Sign In diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx index da0e403..247d46d 100644 --- a/src/components/SignUpForm/index.jsx +++ b/src/components/SignUpForm/index.jsx @@ -15,7 +15,7 @@ export default function SignInForm() { - Sign in + Sign up
- Sign In + Sign Up From baa958cb4b360c56697d108cefbc0baf4b4db692 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 11:38:36 -0800 Subject: [PATCH 04/64] Fix manifest icon filename --- public/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..5fb1630 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -8,12 +8,12 @@ "type": "image/x-icon" }, { - "src": "logo192.png", + "src": "logo-192.png", "type": "image/png", "sizes": "192x192" }, { - "src": "logo512.png", + "src": "logo-512.png", "type": "image/png", "sizes": "512x512" } From fbaf62456fc181e075cd4989172dd9e1c93878b1 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 12:03:57 -0800 Subject: [PATCH 05/64] Update Readme --- README.md | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 0c83cde..dbc31a2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Getting Started with Create React App +# File Upload Web App -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +Front-end web application utilizing Fisker authentication service for file upload service ## Available Scripts @@ -39,24 +39,6 @@ Instead, it will copy all the configuration files and the transitive dependencie You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - ### Advanced Configuration This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) From ec653ca530d32c08ec1c7a1be5f708152e35e7db Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 12:05:32 -0800 Subject: [PATCH 06/64] Add Nodejs version --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c2a112..e176890 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "0.1.0", + "version": "0.1.1", "private": true, "dependencies": { "@material-ui/core": "^4.11.2", @@ -38,5 +38,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "engines": { + "node": "12.20.1" } } From c593b2dfc41e8aaf445963e7d383e2e5122d9829 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 12:06:23 -0800 Subject: [PATCH 07/64] Stub context properties and methods --- src/components/contexts/FileUploadContext.jsx | 25 +++++++++++++ src/components/contexts/UserContext.jsx | 35 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/components/contexts/FileUploadContext.jsx diff --git a/src/components/contexts/FileUploadContext.jsx b/src/components/contexts/FileUploadContext.jsx new file mode 100644 index 0000000..9339657 --- /dev/null +++ b/src/components/contexts/FileUploadContext.jsx @@ -0,0 +1,25 @@ +import React, { useContext, useEffect, useState } from 'react'; + +const FileUploadContext = React.createContext(); + +export const FileUploadProvider = ({ children }) => { + const [file, setFile] = useState(null); + const [uploading, setUploading] = useState(false); + const [progress, setProgress] = useState(0); + + const upload = (file) => { + + }; + + return ( + + {children} + + ); +}; + +export const useFileUploadContext = () => useContext(FileUploadContext); diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index e69de29..90148d9 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -0,0 +1,35 @@ +import React, { useContext, useEffect, useState } from 'react'; + +const UserContext = React.createContext(); + +export const UserProvider = ({ children }) => { + const [signedIn, setSignedIn] = useState(false); + const [user, setUser] = useState(null); + const [token, setToken] = useState(null); + const [signInError, setSignInError] = useState(null); + const [signUpError, setSignUpError] = useState(null); + + const signIn = (email, password) => { + + }; + + const signUp = (email, password, confirmPassword) => { + + }; + + return ( + + {children} + + ); +}; + +export const useUserContext = () => useContext(UserContext); From 552ece45adb72d353b0d8c02d53a7a3ca96e0f2f Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 12:43:14 -0800 Subject: [PATCH 08/64] Remove unused files --- src/components/App/App.css | 38 -------------------------------------- src/logo.svg | 1 - 2 files changed, 39 deletions(-) delete mode 100644 src/components/App/App.css delete mode 100644 src/logo.svg diff --git a/src/components/App/App.css b/src/components/App/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/components/App/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From b0b49fe5e63d40913bebae76bdd6207c8e1a3fdd Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 17:30:25 -0800 Subject: [PATCH 09/64] Add message bar --- src/components/App/index.js | 31 +++++++++++++++++-------------- src/components/MessageBar.jsx | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 src/components/MessageBar.jsx diff --git a/src/components/App/index.js b/src/components/App/index.js index b324cd8..f1a9806 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -4,7 +4,9 @@ import { Switch, Route } from 'react-router-dom'; -import './App.css'; +import { UserProvider } from '../Contexts/UserContext'; +import { ProtectedRoute } from '../Routes/ProtectedRoute'; +import { MessageBar } from '../MessageBar'; const SignInForm = React.lazy(() => import('../SignInForm')); const SignUpForm = React.lazy(() => import('../SignUpForm')); @@ -13,19 +15,20 @@ const FileUploadForm = React.lazy(() => import('../FileUploadForm')); function App() { return ( - - - - - - - - - - - - - + + + + + + + + + + + } /> + + + ); } diff --git a/src/components/MessageBar.jsx b/src/components/MessageBar.jsx new file mode 100644 index 0000000..665b29f --- /dev/null +++ b/src/components/MessageBar.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Snackbar } from "@material-ui/core"; +import { useUserContext } from './Contexts/UserContext'; + +export const MessageBar = () => { + const { error, setError } = useUserContext(); + const open = (error !== null); + + return ( setError(null)}/>) +} From 378d00b220d20b586ca16ce0846b0dab57e667dd Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 17:30:55 -0800 Subject: [PATCH 10/64] Add Contexts --- src/components/contexts/FileUploadContext.jsx | 30 ++--- src/components/contexts/UserContext.jsx | 111 ++++++++++++++---- 2 files changed, 103 insertions(+), 38 deletions(-) diff --git a/src/components/contexts/FileUploadContext.jsx b/src/components/contexts/FileUploadContext.jsx index 9339657..520f2e0 100644 --- a/src/components/contexts/FileUploadContext.jsx +++ b/src/components/contexts/FileUploadContext.jsx @@ -3,23 +3,23 @@ import React, { useContext, useEffect, useState } from 'react'; const FileUploadContext = React.createContext(); export const FileUploadProvider = ({ children }) => { - const [file, setFile] = useState(null); - const [uploading, setUploading] = useState(false); - const [progress, setProgress] = useState(0); - - const upload = (file) => { + const [file, setFile] = useState(null); + const [uploading, setUploading] = useState(false); + const [progress, setProgress] = useState(0); - }; + const upload = (file) => { - return ( - - {children} - - ); + }; + + return ( + + {children} + + ); }; export const useFileUploadContext = () => useContext(FileUploadContext); diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index 90148d9..f9b2292 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -1,35 +1,100 @@ import React, { useContext, useEffect, useState } from 'react'; +const AUTH_URL = 'https://dev-auth.fiskerdps.com'; const UserContext = React.createContext(); export const UserProvider = ({ children }) => { - const [signedIn, setSignedIn] = useState(false); - const [user, setUser] = useState(null); - const [token, setToken] = useState(null); - const [signInError, setSignInError] = useState(null); - const [signUpError, setSignUpError] = useState(null); + const [fetching, setFetching] = useState(false); + const [signedIn, setSignedIn] = useState(false); + const [user, setUser] = useState(null); + const [token, setToken] = useState(null); + const [error, setError] = useState(null); - const signIn = (email, password) => { + const signIn = (username, password) => { + if (!username) throw new Error('Email is required'); + if (!password) throw new Error('Password is required'); + setFetching(true); + setError(null); + return fetch(`${AUTH_URL}/auth/login`, { + method: "POST", + mode: "no-cors", + headers: { + "Content-Type":"text/plain" + }, + body: JSON.stringify({ + username, + password, + }) + }) + .then((response) => { + debugger; + return response.json(); + }) + .then((result) => { + debugger; + setFetching(false); + if (result.error) setError(result.error); + return result; + }) + .catch((error) => { + setError(error.message); + setFetching(false); + return null; + }); + }; - }; - - const signUp = (email, password, confirmPassword) => { + const signUp = (username, password, confirmPassword) => { + if (!username) throw new Error('Email is required'); + if (!password) throw new Error('Password is required'); + if (password !== confirmPassword) throw new Error('Passwords do not match'); + setFetching(true); + setError(null); + return fetch(`${AUTH_URL}/auth/register`, { + method: "POST", + mode: "cors", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username, + password, + }) + }) + .then((response) => { + debugger; + return response.json(); + }) + .then((result) => { + if (result.error) setError(result.error); + setFetching(false); + return result; + }) + .catch((error) => { + setError(error.message); + setFetching(false); + return null; + }); + }; - }; + const signOut = async () => { + setUser(null); + }; - return ( - - {children} - - ); + return ( + + {children} + + ); }; export const useUserContext = () => useContext(UserContext); From 508c41373ee58d6540a70cc4a54e839f459a3b54 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 17:31:10 -0800 Subject: [PATCH 11/64] Add Protected Routes --- src/components/Routes/ProtectedRoute.jsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/components/Routes/ProtectedRoute.jsx diff --git a/src/components/Routes/ProtectedRoute.jsx b/src/components/Routes/ProtectedRoute.jsx new file mode 100644 index 0000000..0779a8b --- /dev/null +++ b/src/components/Routes/ProtectedRoute.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Redirect, Route } from 'react-router-dom'; +import { useUserContext } from '../Contexts/UserContext'; + +export const ProtectedRoute = ({ render, ...others }) => { + const { user, setError } = useUserContext(); + if (!user || !user.sub || user.sub.length === 0) { + setError('Please sign in to access'); + return ; + } + return ; +} \ No newline at end of file From 2e7a241d6dac4d8a19a0efb7588c5784db0b0fa6 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 17:31:40 -0800 Subject: [PATCH 12/64] Add submit handler --- src/components/SignInForm/index.jsx | 25 ++++++++++++++++++++++--- src/components/SignUpForm/index.jsx | 27 ++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index fd7424e..aa22206 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -1,12 +1,27 @@ -import React from 'react'; +import React, { useRef } from 'react'; import { Link as RouterLink } from 'react-router-dom'; import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; +import { useUserContext } from '../Contexts/UserContext'; import useStyles from '../Styles'; export default function SignInForm() { const classes = useStyles(); - + const emailEl = useRef(null); + const passwordEl = useRef(null); + const { fetching, signIn, setError } = useUserContext(); + const onSubmit = async (event) => { + try { + event.preventDefault(); + const username = emailEl.current.value; + const password = passwordEl.current.value; + const result = await signIn(username, password); + } + catch (e) { + setError(e.message); + } + }; + return ( @@ -17,7 +32,7 @@ export default function SignInForm() { Sign in - + diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx index 247d46d..89c5236 100644 --- a/src/components/SignUpForm/index.jsx +++ b/src/components/SignUpForm/index.jsx @@ -1,12 +1,29 @@ -import React from 'react'; +import React, { useRef } from 'react'; import { Link as RouterLink } from 'react-router-dom'; import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; import LockOpenOutlinedIcon from '@material-ui/icons/LockOpenOutlined'; import useStyles from '../Styles'; +import { useUserContext } from '../Contexts/UserContext'; export default function SignInForm() { + const { signUp, fetching, setError } = useUserContext(); const classes = useStyles(); - + const emailEl = useRef(null); + const passwordEl = useRef(null); + const confirmEl = useRef(null); + const onSubmit = async (event) => { + try { + event.preventDefault(); + const email = emailEl.current.value; + const password = passwordEl.current.value; + const confirm = confirmEl.current.value; + const result = await signUp(email, password, confirm); + } + catch (e) { + setError(e.message); + } + }; + return ( @@ -17,7 +34,7 @@ export default function SignInForm() { Sign up - + From 1b39027209931c6c339c9cab77f7f1bd46a341f6 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 19:10:47 -0800 Subject: [PATCH 13/64] Wire up auth api calls --- src/components/contexts/UserContext.jsx | 189 +++++++++++++----------- 1 file changed, 102 insertions(+), 87 deletions(-) diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index f9b2292..8a4a4c4 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -4,97 +4,112 @@ const AUTH_URL = 'https://dev-auth.fiskerdps.com'; const UserContext = React.createContext(); export const UserProvider = ({ children }) => { - const [fetching, setFetching] = useState(false); - const [signedIn, setSignedIn] = useState(false); - const [user, setUser] = useState(null); - const [token, setToken] = useState(null); - const [error, setError] = useState(null); + const [fetching, setFetching] = useState(false); + const [token, setToken] = useState(null); + const [error, setError] = useState(null); - const signIn = (username, password) => { - if (!username) throw new Error('Email is required'); - if (!password) throw new Error('Password is required'); - setFetching(true); - setError(null); - return fetch(`${AUTH_URL}/auth/login`, { - method: "POST", - mode: "no-cors", - headers: { - "Content-Type":"text/plain" - }, - body: JSON.stringify({ - username, - password, - }) - }) - .then((response) => { - debugger; - return response.json(); - }) - .then((result) => { - debugger; - setFetching(false); - if (result.error) setError(result.error); - return result; - }) - .catch((error) => { - setError(error.message); - setFetching(false); - return null; - }); - }; + useEffect(async () => { + if (!sessionStorage) return; + const token = JSON.parse(sessionStorage.getItem("token")); + if (token === null) return; + const { accessToken: { jwtToken }} = token; + const resp = await fetch(`${AUTH_URL}/auth/verify`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ token: jwtToken }) + }); + const result = await resp.json(); + if (!result.authenticated) return; + setToken(token); + }, []); - const signUp = (username, password, confirmPassword) => { - if (!username) throw new Error('Email is required'); - if (!password) throw new Error('Password is required'); - if (password !== confirmPassword) throw new Error('Passwords do not match'); - setFetching(true); - setError(null); - return fetch(`${AUTH_URL}/auth/register`, { - method: "POST", - mode: "cors", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - username, - password, - }) - }) - .then((response) => { - debugger; - return response.json(); - }) - .then((result) => { - if (result.error) setError(result.error); - setFetching(false); - return result; - }) - .catch((error) => { - setError(error.message); - setFetching(false); - return null; - }); - }; + const requestSignIn = (username, password) => fetch(`${AUTH_URL}/auth/login`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username, + password, + }) + }) + .then((response) => response.json()); + + const requestSignUp = (username, password) => fetch(`${AUTH_URL}/auth/register`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username, + password, + }) + }) + .then((response) => response.json()); + + const signIn = (username, password) => { + if (!username) throw new Error('Email is required'); + if (!password) throw new Error('Password is required'); + setFetching(true); + setError(null); + return requestSignIn(username, password) + .then((result) => { + setFetching(false); + if (result.message) throw new Error(result.message); + signedIn(result); + return result; + }) + .catch((error) => { + setError(error.message); + setFetching(false); + return null; + }); + }; - const signOut = async () => { - setUser(null); - }; + const signUp = (username, password, confirmPassword) => { + if (!username) throw new Error('Email is required'); + if (!password) throw new Error('Password is required'); + if (password !== confirmPassword) throw new Error('Passwords do not match'); + setFetching(true); + setError(null); + return requestSignUp(username, password) + .then((result) => { + if (result.message) throw new Error(result.message); + }) + .catch((error) => { + setError(error.message); + setFetching(false); + return null; + }); + }; - return ( - - {children} - - ); + const signOut = async () => { + setToken(null); + if (!sessionStorage) return; + sessionStorage.removeItem("token"); + }; + + const signedIn = (token) => { + setToken(token); + if (!sessionStorage) return; + sessionStorage.setItem("token", JSON.stringify(token)); + } + + return ( + + {children} + + ); }; export const useUserContext = () => useContext(UserContext); From c129d6ac1d0137d7657846ed18b005d8437b0678 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Tue, 5 Jan 2021 19:11:38 -0800 Subject: [PATCH 14/64] Use token var instead of signedIn or user --- src/components/Routes/ProtectedRoute.jsx | 4 ++-- src/components/SignInForm/index.jsx | 10 ++++------ src/components/SignUpForm/index.jsx | 9 +++------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/components/Routes/ProtectedRoute.jsx b/src/components/Routes/ProtectedRoute.jsx index 0779a8b..5e62524 100644 --- a/src/components/Routes/ProtectedRoute.jsx +++ b/src/components/Routes/ProtectedRoute.jsx @@ -3,8 +3,8 @@ import { Redirect, Route } from 'react-router-dom'; import { useUserContext } from '../Contexts/UserContext'; export const ProtectedRoute = ({ render, ...others }) => { - const { user, setError } = useUserContext(); - if (!user || !user.sub || user.sub.length === 0) { + const { token, setError } = useUserContext(); + if (!token) { setError('Please sign in to access'); return ; } diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index aa22206..b8b1849 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -1,7 +1,6 @@ import React, { useRef } from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; -import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; +import { Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; import { useUserContext } from '../Contexts/UserContext'; import useStyles from '../Styles'; @@ -16,8 +15,10 @@ export default function SignInForm() { const username = emailEl.current.value; const password = passwordEl.current.value; const result = await signIn(username, password); + debugger; } catch (e) { + debugger; setError(e.message); } }; @@ -26,9 +27,6 @@ export default function SignInForm() {
- - - Sign in @@ -66,7 +64,7 @@ export default function SignInForm() { className={classes.submit} onClick={onSubmit} > - Sign In + { fetching ? "Signing In..." : "Sign In" } diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx index 89c5236..0959af3 100644 --- a/src/components/SignUpForm/index.jsx +++ b/src/components/SignUpForm/index.jsx @@ -1,7 +1,6 @@ import React, { useRef } from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { Avatar, Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; -import LockOpenOutlinedIcon from '@material-ui/icons/LockOpenOutlined'; +import { Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; import useStyles from '../Styles'; import { useUserContext } from '../Contexts/UserContext'; @@ -18,6 +17,7 @@ export default function SignInForm() { const password = passwordEl.current.value; const confirm = confirmEl.current.value; const result = await signUp(email, password, confirm); + debugger; } catch (e) { setError(e.message); @@ -28,9 +28,6 @@ export default function SignInForm() {
- - - Sign up @@ -78,7 +75,7 @@ export default function SignInForm() { className={classes.submit} disabled={fetching} > - Sign Up + { fetching ? "Signing Up..." : "Sign Up" } From db75494dd84d477558454348b6a18dfe7000ccc1 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 09:11:39 -0800 Subject: [PATCH 15/64] Fix auth verify on page load --- src/components/contexts/UserContext.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index 8a4a4c4..2a12d7d 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -11,7 +11,7 @@ export const UserProvider = ({ children }) => { useEffect(async () => { if (!sessionStorage) return; const token = JSON.parse(sessionStorage.getItem("token")); - if (token === null) return; + if (!token) return; const { accessToken: { jwtToken }} = token; const resp = await fetch(`${AUTH_URL}/auth/verify`, { method: "POST", @@ -21,8 +21,12 @@ export const UserProvider = ({ children }) => { body: JSON.stringify({ token: jwtToken }) }); const result = await resp.json(); - if (!result.authenticated) return; - setToken(token); + if (result.authenticated) { + setToken(token); + } else { + console.log(result); + await signOut(); + } }, []); const requestSignIn = (username, password) => fetch(`${AUTH_URL}/auth/login`, { From 002bad0a919e6708a19dad727a018abcdb287d3a Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 09:23:19 -0800 Subject: [PATCH 16/64] Move api calls into services --- src/components/contexts/UserContext.jsx | 39 +++---------------------- src/services/auth.js | 33 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 src/services/auth.js diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index 2a12d7d..9ea4df3 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useState } from 'react'; +import auth from '../../services/auth'; -const AUTH_URL = 'https://dev-auth.fiskerdps.com'; const UserContext = React.createContext(); export const UserProvider = ({ children }) => { @@ -13,14 +13,7 @@ export const UserProvider = ({ children }) => { const token = JSON.parse(sessionStorage.getItem("token")); if (!token) return; const { accessToken: { jwtToken }} = token; - const resp = await fetch(`${AUTH_URL}/auth/verify`, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ token: jwtToken }) - }); - const result = await resp.json(); + const result = await auth.verify(jwtToken); if (result.authenticated) { setToken(token); } else { @@ -29,36 +22,12 @@ export const UserProvider = ({ children }) => { } }, []); - const requestSignIn = (username, password) => fetch(`${AUTH_URL}/auth/login`, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - username, - password, - }) - }) - .then((response) => response.json()); - - const requestSignUp = (username, password) => fetch(`${AUTH_URL}/auth/register`, { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - username, - password, - }) - }) - .then((response) => response.json()); - const signIn = (username, password) => { if (!username) throw new Error('Email is required'); if (!password) throw new Error('Password is required'); setFetching(true); setError(null); - return requestSignIn(username, password) + return auth.signIn(username, password) .then((result) => { setFetching(false); if (result.message) throw new Error(result.message); @@ -78,7 +47,7 @@ export const UserProvider = ({ children }) => { if (password !== confirmPassword) throw new Error('Passwords do not match'); setFetching(true); setError(null); - return requestSignUp(username, password) + return auth.signUp(username, password) .then((result) => { if (result.message) throw new Error(result.message); }) diff --git a/src/services/auth.js b/src/services/auth.js new file mode 100644 index 0000000..9426bab --- /dev/null +++ b/src/services/auth.js @@ -0,0 +1,33 @@ +const AUTH_URL = 'https://dev-auth.fiskerdps.com'; + +export default { + signIn: (username, password) => fetch(`${AUTH_URL}/auth/login`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username, + password, + }) + }).then((response) => response.json()), + + signUp: (username, password) => fetch(`${AUTH_URL}/auth/register`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + username, + password, + }) + }).then((response) => response.json()), + + verify: (jwt) => fetch(`${AUTH_URL}/auth/verify`, { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ token: jwt }) + }).then((response) => response.json()), +} \ No newline at end of file From 44c56df2c02f97b49f1432ddc8251f4bbb272da4 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 09:31:44 -0800 Subject: [PATCH 17/64] Change to jsx --- src/components/App/{index.js => index.jsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/App/{index.js => index.jsx} (100%) diff --git a/src/components/App/index.js b/src/components/App/index.jsx similarity index 100% rename from src/components/App/index.js rename to src/components/App/index.jsx From 3d50e8c45af8fe50c4ad92a0b18ca8fd92fa10c6 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 10:35:30 -0800 Subject: [PATCH 18/64] Fix authenticated routing issues --- src/components/App/index.jsx | 33 ++++------------------- src/components/Routes/AuthRoute.jsx | 18 +++++++++++++ src/components/Routes/ProtectedRoute.jsx | 4 ++- src/components/Routes/SiteRoutes.jsx | 34 ++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 29 deletions(-) create mode 100644 src/components/Routes/AuthRoute.jsx create mode 100644 src/components/Routes/SiteRoutes.jsx diff --git a/src/components/App/index.jsx b/src/components/App/index.jsx index f1a9806..e914bae 100644 --- a/src/components/App/index.jsx +++ b/src/components/App/index.jsx @@ -1,35 +1,12 @@ -import React, { Suspense } from 'react'; -import { - BrowserRouter, - Switch, - Route -} from 'react-router-dom'; +import React from 'react'; import { UserProvider } from '../Contexts/UserContext'; -import { ProtectedRoute } from '../Routes/ProtectedRoute'; -import { MessageBar } from '../MessageBar'; - -const SignInForm = React.lazy(() => import('../SignInForm')); -const SignUpForm = React.lazy(() => import('../SignUpForm')); -const FileUploadForm = React.lazy(() => import('../FileUploadForm')); +import SiteRoutes from '../Routes/SiteRoutes'; function App() { return ( - - - - - - - - - - - - } /> - - - - + + + ); } diff --git a/src/components/Routes/AuthRoute.jsx b/src/components/Routes/AuthRoute.jsx new file mode 100644 index 0000000..7775630 --- /dev/null +++ b/src/components/Routes/AuthRoute.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Redirect, Route } from 'react-router-dom'; + +export const TYPES = { + PUBLIC: 0, + GUEST: 1, + PROTECTED: 2, +}; + +export const AuthRoute = ({ token, type, ...others }) => { + if (!token && type === TYPES.PROTECTED) { + return ; + } + else if (token && type === TYPES.GUEST) { + return ; + } + return ; +} \ No newline at end of file diff --git a/src/components/Routes/ProtectedRoute.jsx b/src/components/Routes/ProtectedRoute.jsx index 5e62524..8ec3296 100644 --- a/src/components/Routes/ProtectedRoute.jsx +++ b/src/components/Routes/ProtectedRoute.jsx @@ -3,7 +3,9 @@ import { Redirect, Route } from 'react-router-dom'; import { useUserContext } from '../Contexts/UserContext'; export const ProtectedRoute = ({ render, ...others }) => { - const { token, setError } = useUserContext(); + const context = useUserContext(); + const { token, setError } = context; + debugger; if (!token) { setError('Please sign in to access'); return ; diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx new file mode 100644 index 0000000..e77052c --- /dev/null +++ b/src/components/Routes/SiteRoutes.jsx @@ -0,0 +1,34 @@ +import React, { Suspense } from 'react'; +import { + BrowserRouter, + Switch, + Route +} from 'react-router-dom'; + +import { AuthRoute, TYPES } from '../Routes/AuthRoute' +import { MessageBar } from '../MessageBar'; +import { useUserContext } from '../Contexts/UserContext'; + +const SignInForm = React.lazy(() => import('../SignInForm')); +const SignUpForm = React.lazy(() => import('../SignUpForm')); +const FileUploadForm = React.lazy(() => import('../FileUploadForm')); + +const SiteRoutes = () => { + const { token } = useUserContext(); + console.log('SiteRoutes', token); + return ( + + + + + } type={TYPES.GUEST} token={token} /> + } type={TYPES.GUEST} token={token} /> + } type={TYPES.PROTECTED} token={token} /> + + + + ); +}; + + +export default SiteRoutes; \ No newline at end of file From c9e4d2670275ad1ce5eac9866be0f91be5549954 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 10:36:39 -0800 Subject: [PATCH 19/64] Clean up debugger --- src/components/Routes/ProtectedRoute.jsx | 1 - src/components/SignInForm/index.jsx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/Routes/ProtectedRoute.jsx b/src/components/Routes/ProtectedRoute.jsx index 8ec3296..e2cded1 100644 --- a/src/components/Routes/ProtectedRoute.jsx +++ b/src/components/Routes/ProtectedRoute.jsx @@ -5,7 +5,6 @@ import { useUserContext } from '../Contexts/UserContext'; export const ProtectedRoute = ({ render, ...others }) => { const context = useUserContext(); const { token, setError } = context; - debugger; if (!token) { setError('Please sign in to access'); return ; diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index b8b1849..d734e57 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -18,7 +18,6 @@ export default function SignInForm() { debugger; } catch (e) { - debugger; setError(e.message); } }; From f2deb29ad854c952bc76b4f9171c945f9218c0a9 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 10:42:04 -0800 Subject: [PATCH 20/64] Fix async warning --- src/components/contexts/UserContext.jsx | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index 9ea4df3..48831b3 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -8,18 +8,22 @@ export const UserProvider = ({ children }) => { const [token, setToken] = useState(null); const [error, setError] = useState(null); - useEffect(async () => { + useEffect(() => { if (!sessionStorage) return; const token = JSON.parse(sessionStorage.getItem("token")); if (!token) return; const { accessToken: { jwtToken }} = token; - const result = await auth.verify(jwtToken); - if (result.authenticated) { - setToken(token); - } else { - console.log(result); - await signOut(); - } + const verifyToken = async (jwt) => { + debugger; + const result = await auth.verify(jwtToken); + if (result.authenticated) { + setToken(token); + } else { + console.log(result); + await signOut(); + } + }; + verifyToken(jwtToken); }, []); const signIn = (username, password) => { From 70c0714559b5beb0f6c64332f06ba8f6bf8aa002 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 11:01:31 -0800 Subject: [PATCH 21/64] Wire up sign out --- src/components/FileUploadForm/index.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx index de0d637..fa0c176 100644 --- a/src/components/FileUploadForm/index.jsx +++ b/src/components/FileUploadForm/index.jsx @@ -1,12 +1,14 @@ import React from 'react'; import { Link as RouterLink } from 'react-router-dom'; -import { Container, CssBaseline, Grid, Link, Typography } from '@material-ui/core'; +import { Button, Container, CssBaseline, Grid, Link, Typography } from '@material-ui/core'; import { DropzoneAreaBase } from 'material-ui-dropzone'; +import { useUserContext } from '../Contexts/UserContext'; import useStyles from '../Styles'; export default function FileUploadForm() { const classes = useStyles(); - + const { signOut } = useUserContext(); + return ( @@ -17,10 +19,8 @@ export default function FileUploadForm() { - - - {"Sign Out"} - + + From d7616ca577b04a186fec7ea17a69dcf7d225e23f Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 11:07:19 -0800 Subject: [PATCH 22/64] Sign up should also sign in --- src/components/contexts/UserContext.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index 48831b3..e0c11b3 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -54,6 +54,7 @@ export const UserProvider = ({ children }) => { return auth.signUp(username, password) .then((result) => { if (result.message) throw new Error(result.message); + return signIn(username, password); }) .catch((error) => { setError(error.message); From e9e2195b14796be2622d35c1a00d5119152aaae6 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 11:16:06 -0800 Subject: [PATCH 23/64] Remove debugger --- src/components/SignInForm/index.jsx | 5 ++--- src/components/SignUpForm/index.jsx | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx index d734e57..ec5fd54 100644 --- a/src/components/SignInForm/index.jsx +++ b/src/components/SignInForm/index.jsx @@ -1,7 +1,7 @@ import React, { useRef } from 'react'; import { Link as RouterLink } from 'react-router-dom'; import { Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; -import { useUserContext } from '../Contexts/UserContext'; +import { useUserContext } from '../Contexts/UserContext'; import useStyles from '../Styles'; export default function SignInForm() { @@ -14,8 +14,7 @@ export default function SignInForm() { event.preventDefault(); const username = emailEl.current.value; const password = passwordEl.current.value; - const result = await signIn(username, password); - debugger; + await signIn(username, password); } catch (e) { setError(e.message); diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx index 0959af3..a6b838b 100644 --- a/src/components/SignUpForm/index.jsx +++ b/src/components/SignUpForm/index.jsx @@ -16,8 +16,7 @@ export default function SignInForm() { const email = emailEl.current.value; const password = passwordEl.current.value; const confirm = confirmEl.current.value; - const result = await signUp(email, password, confirm); - debugger; + await signUp(email, password, confirm); } catch (e) { setError(e.message); From d812daa1eaf6b2cda06befcd2257eb68c886f1b5 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 18:22:33 -0800 Subject: [PATCH 24/64] Add UserContext unit test for signup --- package-lock.json | 184 +++++++++++-------- package.json | 4 + src/components/contexts/UserContext.test.jsx | 71 +++++++ src/services/__mocks__/auth.js | 17 ++ 4 files changed, 200 insertions(+), 76 deletions(-) create mode 100644 src/components/contexts/UserContext.test.jsx create mode 100644 src/services/__mocks__/auth.js diff --git a/package-lock.json b/package-lock.json index 4b6b58e..ceaac87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -8119,81 +8119,6 @@ "istanbul-lib-report": "^3.0.0" } }, - "jest": { - "version": "26.6.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz", - "integrity": "sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA==", - "requires": { - "@jest/core": "^26.6.0", - "import-local": "^3.0.2", - "jest-cli": "^26.6.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "jest-changed-files": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", @@ -12736,6 +12661,113 @@ "webpack-dev-server": "3.11.0", "webpack-manifest-plugin": "2.2.0", "workbox-webpack-plugin": "5.1.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "jest": { + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz", + "integrity": "sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA==", + "requires": { + "@jest/core": "^26.6.0", + "import-local": "^3.0.2", + "jest-cli": "^26.6.0" + }, + "dependencies": { + "jest-cli": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "requires": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + } + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "react-shallow-renderer": { + "version": "16.14.1", + "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz", + "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "react-is": "^16.12.0 || ^17.0.0" + } + }, + "react-test-renderer": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.1.tgz", + "integrity": "sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "react-is": "^17.0.1", + "react-shallow-renderer": "^16.13.1", + "scheduler": "^0.20.1" + }, + "dependencies": { + "react-is": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "dev": true + } } }, "react-transition-group": { diff --git a/package.json b/package.json index e176890..e187fb1 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", + "test:debug": "react-scripts --inspect-brk test --runInBand --no-cache", "eject": "react-scripts eject" }, "eslintConfig": { @@ -41,5 +42,8 @@ }, "engines": { "node": "12.20.1" + }, + "devDependencies": { + "react-test-renderer": "^17.0.1" } } diff --git a/src/components/contexts/UserContext.test.jsx b/src/components/contexts/UserContext.test.jsx new file mode 100644 index 0000000..7a2c41d --- /dev/null +++ b/src/components/contexts/UserContext.test.jsx @@ -0,0 +1,71 @@ +import {render, cleanup, screen, fireEvent, waitFor} from '@testing-library/react' +import { UserProvider, useUserContext } from '../Contexts/UserContext'; +import auth from "../../services/auth"; + +jest.mock('../../services/auth'); + +describe('UseContext', () => { + + describe("Signup", () => { + beforeEach(() => { + const TestComp = () => { + const { signUp, error, fetching } = useUserContext(); + return ( + <> +
{error}
+
{fetching.toString()}
+ + + +
+ +
+`; diff --git a/src/components/SignInForm/index.test.jsx b/src/components/SignInForm/index.test.jsx new file mode 100644 index 0000000..02d2af9 --- /dev/null +++ b/src/components/SignInForm/index.test.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import { BrowserRouter } from 'react-router-dom'; +import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" +jest.mock("../Contexts/UserContext"); +import { useUserContext, UserProvider } from "../Contexts/UserContext"; +import SignInForm from './index'; + +describe("Sign In Form", () => { + + it("Should render", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + cleanup(); + }) +}) \ No newline at end of file diff --git a/src/components/contexts/__mocks__/UserContext.jsx b/src/components/contexts/__mocks__/UserContext.jsx new file mode 100644 index 0000000..1968079 --- /dev/null +++ b/src/components/contexts/__mocks__/UserContext.jsx @@ -0,0 +1,19 @@ +import React from 'react'; + +export const UserProvider = ({ children }) => { + return ( +
+ {children} +
+ ); +}; + +export const useUserContext = () => ({ + fetching: false, + token: null, + error: null, + setError: jest.fn(), + signIn: jest.fn(), + signUp: jest.fn(), + signOut: jest.fn(), +}); From 388ea68400bcf4d715b27f0fdd17ba2cac45726e Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 19:55:57 -0800 Subject: [PATCH 29/64] Update sign in form test --- .../{index.test.jsx => SignInForm.test.jsx} | 0 .../__snapshots__/index.test.jsx.snap | 145 ------------------ 2 files changed, 145 deletions(-) rename src/components/SignInForm/{index.test.jsx => SignInForm.test.jsx} (100%) delete mode 100644 src/components/SignInForm/__snapshots__/index.test.jsx.snap diff --git a/src/components/SignInForm/index.test.jsx b/src/components/SignInForm/SignInForm.test.jsx similarity index 100% rename from src/components/SignInForm/index.test.jsx rename to src/components/SignInForm/SignInForm.test.jsx diff --git a/src/components/SignInForm/__snapshots__/index.test.jsx.snap b/src/components/SignInForm/__snapshots__/index.test.jsx.snap deleted file mode 100644 index e99b269..0000000 --- a/src/components/SignInForm/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,145 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Sign In Form Should render 1`] = ` -
-
-
-

- Sign in -

-
-
- -
- - -
-
-
- -
- - -
-
- - -
-
-
-
-`; From a5515798d4d489d0276c2d3b63a0fe9fcf434ccd Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 19:56:46 -0800 Subject: [PATCH 30/64] Add sign up form snapshot test --- src/components/SignUpForm/SignUpForm.test.jsx | 15 ++ .../__snapshots__/SignUpForm.test.jsx.snap | 189 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 src/components/SignUpForm/SignUpForm.test.jsx create mode 100644 src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap diff --git a/src/components/SignUpForm/SignUpForm.test.jsx b/src/components/SignUpForm/SignUpForm.test.jsx new file mode 100644 index 0000000..d08d480 --- /dev/null +++ b/src/components/SignUpForm/SignUpForm.test.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import { BrowserRouter } from 'react-router-dom'; +import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" +jest.mock("../Contexts/UserContext"); +import { useUserContext, UserProvider } from "../Contexts/UserContext"; +import SignUpForm from './index'; + +describe("Sign Up Form", () => { + + it("Should render", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + cleanup(); + }) +}) \ No newline at end of file diff --git a/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap b/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap new file mode 100644 index 0000000..1e1b0d8 --- /dev/null +++ b/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap @@ -0,0 +1,189 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Sign Up Form Should render 1`] = ` +
+
+
+

+ Sign up +

+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+`; From 243c70e4d556d16affc8488a9a25eb22f5f4ea76 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 19:56:57 -0800 Subject: [PATCH 31/64] Update sign in form snapshot --- .../__snapshots__/SignInForm.test.jsx.snap | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap diff --git a/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap b/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap new file mode 100644 index 0000000..e99b269 --- /dev/null +++ b/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap @@ -0,0 +1,145 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Sign In Form Should render 1`] = ` +
+
+
+

+ Sign in +

+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+`; From d2a8d74dd099bf50dc1ef8a98a9edaf107e3a0d8 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:05:00 -0800 Subject: [PATCH 32/64] Add sign out link --- src/components/FileUploadForm/index.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx index fa0c176..77f8fcd 100644 --- a/src/components/FileUploadForm/index.jsx +++ b/src/components/FileUploadForm/index.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Link as RouterLink } from 'react-router-dom'; import { Button, Container, CssBaseline, Grid, Link, Typography } from '@material-ui/core'; import { DropzoneAreaBase } from 'material-ui-dropzone'; import { useUserContext } from '../Contexts/UserContext'; From c098538b9e51bcd025792181ff47806835fc61ed Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:05:16 -0800 Subject: [PATCH 33/64] Add File upload form snapshot test --- .../FileUploadForm/FileUploadForm.test.js | 15 ++++ .../__snapshots__/FileUploadForm.test.js.snap | 78 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/components/FileUploadForm/FileUploadForm.test.js create mode 100644 src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap diff --git a/src/components/FileUploadForm/FileUploadForm.test.js b/src/components/FileUploadForm/FileUploadForm.test.js new file mode 100644 index 0000000..527d960 --- /dev/null +++ b/src/components/FileUploadForm/FileUploadForm.test.js @@ -0,0 +1,15 @@ +import React from "react"; +import { BrowserRouter } from 'react-router-dom'; +import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" +jest.mock("../Contexts/UserContext"); +import { useUserContext, UserProvider } from "../Contexts/UserContext"; +import FileUploadForm from './index'; + +describe("File Upload Form", () => { + + it("Should render", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + cleanup(); + }) +}) \ No newline at end of file diff --git a/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap new file mode 100644 index 0000000..70916a3 --- /dev/null +++ b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`File Upload Form Should render 1`] = ` +
+
+
+

+ Upload File +

+
+
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+
+ +
+
+
+
+
+
+`; From 527c7c2b7b0bbf011a0b181d29524eaf63fd668f Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:07:38 -0800 Subject: [PATCH 34/64] Disable console log --- src/services/__mocks__/auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/__mocks__/auth.js b/src/services/__mocks__/auth.js index 909b992..e8b4ca4 100644 --- a/src/services/__mocks__/auth.js +++ b/src/services/__mocks__/auth.js @@ -3,7 +3,7 @@ let signUpResponse = {}; let verifyResponse = {}; const logResponse = (response) => { - console.log('logResponse', response); + // console.log('logResponse', response); return response; }; From 4abeb0e9a0e4b07b383785e6caf9a7d113c39ad4 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:12:15 -0800 Subject: [PATCH 35/64] Rearrange mocks --- src/components/FileUploadForm/FileUploadForm.test.js | 4 +++- src/components/SignInForm/SignInForm.test.jsx | 1 + src/components/SignUpForm/SignUpForm.test.jsx | 3 ++- src/components/contexts/UserContext.test.jsx | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/FileUploadForm/FileUploadForm.test.js b/src/components/FileUploadForm/FileUploadForm.test.js index 527d960..ec1f6cf 100644 --- a/src/components/FileUploadForm/FileUploadForm.test.js +++ b/src/components/FileUploadForm/FileUploadForm.test.js @@ -1,7 +1,9 @@ +jest.mock("../Contexts/UserContext"); +jest.mock("../Contexts/UserContext"); + import React from "react"; import { BrowserRouter } from 'react-router-dom'; import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" -jest.mock("../Contexts/UserContext"); import { useUserContext, UserProvider } from "../Contexts/UserContext"; import FileUploadForm from './index'; diff --git a/src/components/SignInForm/SignInForm.test.jsx b/src/components/SignInForm/SignInForm.test.jsx index 02d2af9..4a91d47 100644 --- a/src/components/SignInForm/SignInForm.test.jsx +++ b/src/components/SignInForm/SignInForm.test.jsx @@ -2,6 +2,7 @@ import React from "react"; import { BrowserRouter } from 'react-router-dom'; import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" jest.mock("../Contexts/UserContext"); + import { useUserContext, UserProvider } from "../Contexts/UserContext"; import SignInForm from './index'; diff --git a/src/components/SignUpForm/SignUpForm.test.jsx b/src/components/SignUpForm/SignUpForm.test.jsx index d08d480..6b0eba9 100644 --- a/src/components/SignUpForm/SignUpForm.test.jsx +++ b/src/components/SignUpForm/SignUpForm.test.jsx @@ -1,7 +1,8 @@ +jest.mock("../Contexts/UserContext"); + import React from "react"; import { BrowserRouter } from 'react-router-dom'; import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" -jest.mock("../Contexts/UserContext"); import { useUserContext, UserProvider } from "../Contexts/UserContext"; import SignUpForm from './index'; diff --git a/src/components/contexts/UserContext.test.jsx b/src/components/contexts/UserContext.test.jsx index 7479165..37e26c3 100644 --- a/src/components/contexts/UserContext.test.jsx +++ b/src/components/contexts/UserContext.test.jsx @@ -1,11 +1,11 @@ +jest.mock("../../services/auth"); + import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" import { UserProvider, useUserContext } from "../Contexts/UserContext"; import auth from "../../services/auth"; const TEST_TOKEN = { accessToken: { jwtToken: "TEST" }}; -jest.mock("../../services/auth"); - describe("UseContext", () => { describe("Signup", () => { From 0454317ecefe4cde178f60d38e18fc6e61106a94 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:17:52 -0800 Subject: [PATCH 36/64] Update imports --- src/components/FileUploadForm/FileUploadForm.test.js | 5 +---- src/components/SignInForm/SignInForm.test.jsx | 5 ++--- src/components/SignUpForm/SignUpForm.test.jsx | 4 +--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/FileUploadForm/FileUploadForm.test.js b/src/components/FileUploadForm/FileUploadForm.test.js index ec1f6cf..4b3c5fb 100644 --- a/src/components/FileUploadForm/FileUploadForm.test.js +++ b/src/components/FileUploadForm/FileUploadForm.test.js @@ -1,10 +1,7 @@ jest.mock("../Contexts/UserContext"); -jest.mock("../Contexts/UserContext"); -import React from "react"; import { BrowserRouter } from 'react-router-dom'; -import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" -import { useUserContext, UserProvider } from "../Contexts/UserContext"; +import {render, cleanup} from "@testing-library/react" import FileUploadForm from './index'; describe("File Upload Form", () => { diff --git a/src/components/SignInForm/SignInForm.test.jsx b/src/components/SignInForm/SignInForm.test.jsx index 4a91d47..d31b6d4 100644 --- a/src/components/SignInForm/SignInForm.test.jsx +++ b/src/components/SignInForm/SignInForm.test.jsx @@ -1,9 +1,8 @@ +jest.mock("../Contexts/UserContext"); + import React from "react"; import { BrowserRouter } from 'react-router-dom'; import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" -jest.mock("../Contexts/UserContext"); - -import { useUserContext, UserProvider } from "../Contexts/UserContext"; import SignInForm from './index'; describe("Sign In Form", () => { diff --git a/src/components/SignUpForm/SignUpForm.test.jsx b/src/components/SignUpForm/SignUpForm.test.jsx index 6b0eba9..07dce69 100644 --- a/src/components/SignUpForm/SignUpForm.test.jsx +++ b/src/components/SignUpForm/SignUpForm.test.jsx @@ -1,9 +1,7 @@ jest.mock("../Contexts/UserContext"); -import React from "react"; import { BrowserRouter } from 'react-router-dom'; -import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" -import { useUserContext, UserProvider } from "../Contexts/UserContext"; +import {render, cleanup} from "@testing-library/react" import SignUpForm from './index'; describe("Sign Up Form", () => { From 87e673576d74e13cbc0fd1f7fe9926607b377bd5 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:20:11 -0800 Subject: [PATCH 37/64] Clean up --- src/components/FileUploadForm/FileUploadForm.test.js | 2 +- src/components/SignInForm/SignInForm.test.jsx | 2 +- src/components/SignUpForm/SignUpForm.test.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/FileUploadForm/FileUploadForm.test.js b/src/components/FileUploadForm/FileUploadForm.test.js index 4b3c5fb..6c7e351 100644 --- a/src/components/FileUploadForm/FileUploadForm.test.js +++ b/src/components/FileUploadForm/FileUploadForm.test.js @@ -1,7 +1,7 @@ jest.mock("../Contexts/UserContext"); import { BrowserRouter } from 'react-router-dom'; -import {render, cleanup} from "@testing-library/react" +import { render, cleanup } from "@testing-library/react" import FileUploadForm from './index'; describe("File Upload Form", () => { diff --git a/src/components/SignInForm/SignInForm.test.jsx b/src/components/SignInForm/SignInForm.test.jsx index d31b6d4..45c15d3 100644 --- a/src/components/SignInForm/SignInForm.test.jsx +++ b/src/components/SignInForm/SignInForm.test.jsx @@ -2,7 +2,7 @@ jest.mock("../Contexts/UserContext"); import React from "react"; import { BrowserRouter } from 'react-router-dom'; -import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" +import { render, cleanup } from "@testing-library/react" import SignInForm from './index'; describe("Sign In Form", () => { diff --git a/src/components/SignUpForm/SignUpForm.test.jsx b/src/components/SignUpForm/SignUpForm.test.jsx index 07dce69..3e69fdc 100644 --- a/src/components/SignUpForm/SignUpForm.test.jsx +++ b/src/components/SignUpForm/SignUpForm.test.jsx @@ -1,7 +1,7 @@ jest.mock("../Contexts/UserContext"); import { BrowserRouter } from 'react-router-dom'; -import {render, cleanup} from "@testing-library/react" +import { render, cleanup } from "@testing-library/react" import SignUpForm from './index'; describe("Sign Up Form", () => { From 85ec4d5728ecff9e496398bfaddd5b0e42a6a305 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 20:58:45 -0800 Subject: [PATCH 38/64] Clean up --- src/components/Routes/SiteRoutes.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx index e77052c..f269c39 100644 --- a/src/components/Routes/SiteRoutes.jsx +++ b/src/components/Routes/SiteRoutes.jsx @@ -2,7 +2,6 @@ import React, { Suspense } from 'react'; import { BrowserRouter, Switch, - Route } from 'react-router-dom'; import { AuthRoute, TYPES } from '../Routes/AuthRoute' @@ -15,7 +14,6 @@ const FileUploadForm = React.lazy(() => import('../FileUploadForm')); const SiteRoutes = () => { const { token } = useUserContext(); - console.log('SiteRoutes', token); return ( From 75eeb0e4e9c70d03d63048d752606c09ce69d85f Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 21:54:09 -0800 Subject: [PATCH 39/64] Update app routes test --- src/components/App/App.test.js | 84 +- .../App/__snapshots__/App.test.js.snap | 732 ++++++++++++++++++ .../__snapshots__/FileUploadForm.test.js.snap | 2 +- src/components/FileUploadForm/index.jsx | 2 +- .../contexts/__mocks__/UserContext.jsx | 22 +- 5 files changed, 830 insertions(+), 12 deletions(-) create mode 100644 src/components/App/__snapshots__/App.test.js.snap diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 7892e7b..a9e2c6a 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -1,8 +1,78 @@ -import { render, screen } from '@testing-library/react'; -import App from '.'; +jest.mock("../Contexts/UserContext"); -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); +import { render, screen, cleanup, waitFor } from "@testing-library/react" +import { setToken } from "../Contexts/UserContext"; +import App from "."; + +const TEST_TOKEN = { accessToken: { jwtToken: "TEST" }}; + +describe.only("App", () => { + + it ("Route / unauthenticated", async () => { + setToken(null); + window.history.pushState({}, "", "/"); + const { container } = render(); + // need 2 cycles to render due to routes + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); + cleanup(); + }); + + it ("Route /signup unauthenticated", async () => { + setToken(null); + window.history.pushState({}, "", "/signup"); + const { container } = render(); + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Sign up"); + cleanup(); + }); + + it ("Route /home unauthenticated", async () => { + setToken(null); + window.history.pushState({}, "", "/home"); + const { container } = render(); + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); + cleanup(); + }); + + it ("Route / authenticated", async () => { + setToken(TEST_TOKEN); + window.history.pushState({}, "", "/"); + const { container } = render(); + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + cleanup(); + }); + + it ("Route /signup authenticated", async () => { + setToken(TEST_TOKEN); + window.history.pushState({}, "", "/signup"); + const { container } = render(); + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + cleanup(); + }); + + it ("Route /home authenticated", async () => { + setToken(TEST_TOKEN); + window.history.pushState({}, "", "/home"); + const { container } = render(); + await waitFor(() => {}); + await waitFor(() => {}); + expect(container).toMatchSnapshot(); + expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + cleanup(); + }); + +}) \ No newline at end of file diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap new file mode 100644 index 0000000..a8a7e6f --- /dev/null +++ b/src/components/App/__snapshots__/App.test.js.snap @@ -0,0 +1,732 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`App Route / authenticated 1`] = ` +
+
+
+
+

+ Upload file +

+
+
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`App Route / unauthenticated 1`] = ` +
+
+
+
+

+ Sign in +

+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+
+`; + +exports[`App Route /home authenticated 1`] = ` +
+
+
+
+

+ Upload file +

+
+
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`App Route /home unauthenticated 1`] = ` +
+
+
+
+

+ Sign in +

+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+
+`; + +exports[`App Route /signup authenticated 1`] = ` +
+
+
+
+

+ Upload file +

+
+
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`App Route /signup unauthenticated 1`] = ` +
+
+
+
+

+ Sign up +

+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+
+
+`; diff --git a/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap index 70916a3..16ca995 100644 --- a/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap +++ b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap @@ -11,7 +11,7 @@ exports[`File Upload Form Should render 1`] = `

- Upload File + Upload file

- Upload File + Upload file diff --git a/src/components/contexts/__mocks__/UserContext.jsx b/src/components/contexts/__mocks__/UserContext.jsx index 1968079..73e7b45 100644 --- a/src/components/contexts/__mocks__/UserContext.jsx +++ b/src/components/contexts/__mocks__/UserContext.jsx @@ -1,5 +1,9 @@ import React from 'react'; +let token = null; +let fetching = false; +let error = null; + export const UserProvider = ({ children }) => { return (
@@ -9,11 +13,23 @@ export const UserProvider = ({ children }) => { }; export const useUserContext = () => ({ - fetching: false, - token: null, - error: null, + token, + fetching, + error, setError: jest.fn(), signIn: jest.fn(), signUp: jest.fn(), signOut: jest.fn(), }); + +export const setToken = (val) => { + token = val; +}; + +export const setFetching = (val) => { + fetching = val; +}; + +export const setError = (val) => { + error = val; +}; From 812b91ee7441476cb0e01faf2d8fbcac745ad3d5 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Wed, 6 Jan 2021 22:00:23 -0800 Subject: [PATCH 40/64] Fix build warnings --- src/components/FileUploadForm/index.jsx | 2 +- src/components/contexts/UserContext.jsx | 2 +- src/services/auth.js | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/FileUploadForm/index.jsx b/src/components/FileUploadForm/index.jsx index 9e528ac..e9ea0e3 100644 --- a/src/components/FileUploadForm/index.jsx +++ b/src/components/FileUploadForm/index.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button, Container, CssBaseline, Grid, Link, Typography } from '@material-ui/core'; +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'; diff --git a/src/components/contexts/UserContext.jsx b/src/components/contexts/UserContext.jsx index b7b3608..9161310 100644 --- a/src/components/contexts/UserContext.jsx +++ b/src/components/contexts/UserContext.jsx @@ -22,7 +22,7 @@ export const UserProvider = ({ children }) => { await signOut(); } }; - verifyToken(); + verifyToken(jwtToken); return () => {}; }, []); diff --git a/src/services/auth.js b/src/services/auth.js index 9426bab..3de3a81 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -1,6 +1,6 @@ const AUTH_URL = 'https://dev-auth.fiskerdps.com'; -export default { +const auth = { signIn: (username, password) => fetch(`${AUTH_URL}/auth/login`, { method: "POST", headers: { @@ -30,4 +30,6 @@ export default { }, body: JSON.stringify({ token: jwt }) }).then((response) => response.json()), -} \ No newline at end of file +}; + +export default auth; From bd7d15721d9ce57b9f1492b7fc7bf49d05867f48 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 08:10:09 -0800 Subject: [PATCH 41/64] Refactor rendering --- src/components/App/App.test.js | 57 +++++++++++++++------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index a9e2c6a..629f5c7 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -1,75 +1,68 @@ jest.mock("../Contexts/UserContext"); -import { render, screen, cleanup, waitFor } from "@testing-library/react" +import { render, screen, cleanup, waitForElementToBeRemoved, waitFor } from "@testing-library/react" import { setToken } from "../Contexts/UserContext"; import App from "."; const TEST_TOKEN = { accessToken: { jwtToken: "TEST" }}; +const LOADING_STATUS = "Loading..."; + +const renderRoute = async (route) => { + window.history.pushState({}, "", route); + const { container } = render(); + if (screen.queryByText(LOADING_STATUS)) { + await waitForElementToBeRemoved(() => screen.getByText(LOADING_STATUS)); + } else { + await waitFor(() => {}); + } + return container; +}; describe.only("App", () => { - it ("Route / unauthenticated", async () => { + it("Route / unauthenticated", async () => { setToken(null); - window.history.pushState({}, "", "/"); - const { container } = render(); - // need 2 cycles to render due to routes - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); cleanup(); }); - it ("Route /signup unauthenticated", async () => { + it("Route /signup unauthenticated", async () => { setToken(null); - window.history.pushState({}, "", "/signup"); - const { container } = render(); - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/signup"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign up"); cleanup(); }); - it ("Route /home unauthenticated", async () => { + it("Route /home unauthenticated", async () => { setToken(null); - window.history.pushState({}, "", "/home"); - const { container } = render(); - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/home"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); cleanup(); }); - it ("Route / authenticated", async () => { + it("Route / authenticated", async () => { setToken(TEST_TOKEN); - window.history.pushState({}, "", "/"); - const { container } = render(); - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); cleanup(); }); - it ("Route /signup authenticated", async () => { + it("Route /signup authenticated", async () => { setToken(TEST_TOKEN); - window.history.pushState({}, "", "/signup"); - const { container } = render(); - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/signup"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); cleanup(); }); - it ("Route /home authenticated", async () => { + it("Route /home authenticated", async () => { setToken(TEST_TOKEN); - window.history.pushState({}, "", "/home"); - const { container } = render(); - await waitFor(() => {}); - await waitFor(() => {}); + const container = await renderRoute("/home"); expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); cleanup(); From 8fc6b3b6d851f55417807a4b57ed3d069011faa9 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 08:11:37 -0800 Subject: [PATCH 42/64] Clean up --- src/components/App/App.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 629f5c7..67ca594 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -18,7 +18,7 @@ const renderRoute = async (route) => { return container; }; -describe.only("App", () => { +describe("App", () => { it("Route / unauthenticated", async () => { setToken(null); From 0ae42bf51d973f5eaa04d6a4e26e21475495b60a Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 14:10:58 -0800 Subject: [PATCH 43/64] Wire up file upload form --- package-lock.json | 8 ++++ package.json | 1 + src/components/FileUploadForm/index.jsx | 43 ++++++++++++------ src/components/ModalProgressBar/index.jsx | 44 +++++++++++++++++++ src/components/Routes/SiteRoutes.jsx | 2 +- src/components/contexts/FileUploadContext.jsx | 34 +++++++++++++- src/services/uploadFile.js | 29 ++++++++++++ 7 files changed, 145 insertions(+), 16 deletions(-) create mode 100644 src/components/ModalProgressBar/index.jsx create mode 100644 src/services/uploadFile.js 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); +}; From a2e27ca6a105fbbf3ce3991181a3eef510cb92a8 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 15:19:08 -0800 Subject: [PATCH 44/64] Update Upload form tests with mocked provider --- src/components/App/App.test.js | 1 + .../App/__snapshots__/App.test.js.snap | 330 +++++++++--------- src/components/Routes/SiteRoutes.jsx | 2 +- .../contexts/__mocks__/FileUploadContext.jsx | 21 ++ 4 files changed, 194 insertions(+), 160 deletions(-) create mode 100644 src/components/contexts/__mocks__/FileUploadContext.jsx diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 67ca594..1068b72 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -1,4 +1,5 @@ jest.mock("../Contexts/UserContext"); +jest.mock("../Contexts/FileUploadContext"); import { render, screen, cleanup, waitForElementToBeRemoved, waitFor } from "@testing-library/react" import { setToken } from "../Contexts/UserContext"; diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap index a8a7e6f..f4284ec 100644 --- a/src/components/App/__snapshots__/App.test.js.snap +++ b/src/components/App/__snapshots__/App.test.js.snap @@ -16,65 +16,69 @@ exports[`App Route / authenticated 1`] = ` > Upload file -
+ +
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+
+
- -
-

- Drag and drop a file here or click -

- -
+ Sign Out + + +
-
-
- -
-
- +
@@ -245,65 +249,69 @@ exports[`App Route /home authenticated 1`] = ` > Upload file -
+ +
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+ +
- -
-

- Drag and drop a file here or click -

- -
+ Sign Out + + +
-
-
- -
-
- +
@@ -474,65 +482,69 @@ exports[`App Route /signup authenticated 1`] = ` > Upload file -
+ +
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+ +
- -
-

- Drag and drop a file here or click -

- -
+ Sign Out + + +
-
-
- -
-
- +
diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx index 5b3fc89..f269c39 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.PUBLIC} token={token} /> + } type={TYPES.PROTECTED} token={token} />
diff --git a/src/components/contexts/__mocks__/FileUploadContext.jsx b/src/components/contexts/__mocks__/FileUploadContext.jsx new file mode 100644 index 0000000..ca3d223 --- /dev/null +++ b/src/components/contexts/__mocks__/FileUploadContext.jsx @@ -0,0 +1,21 @@ +import React from "react"; + +let uploading = false; +let progress = 0; +let status = null; + +export const FileUploadProvider = ({ children }) => { + return ( +
+ {children} +
+ ); +}; + +export const useFileUploadContext = () => ({ + uploading, + progress, + status, + upload: jest.fn(), + cancel: jest.fn(), +}); From 116581c7ddc1f1b792482f6cf963ff1498645331 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 15:25:01 -0800 Subject: [PATCH 45/64] Update snapshot for mock FileUploadProvider --- .../FileUploadForm/FileUploadForm.test.js | 1 + .../__snapshots__/FileUploadForm.test.js.snap | 110 +++++++++--------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/components/FileUploadForm/FileUploadForm.test.js b/src/components/FileUploadForm/FileUploadForm.test.js index 6c7e351..25f97fe 100644 --- a/src/components/FileUploadForm/FileUploadForm.test.js +++ b/src/components/FileUploadForm/FileUploadForm.test.js @@ -1,4 +1,5 @@ jest.mock("../Contexts/UserContext"); +jest.mock("../Contexts/FileUploadContext"); import { BrowserRouter } from 'react-router-dom'; import { render, cleanup } from "@testing-library/react" diff --git a/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap index 16ca995..206cbf7 100644 --- a/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap +++ b/src/components/FileUploadForm/__snapshots__/FileUploadForm.test.js.snap @@ -13,65 +13,69 @@ exports[`File Upload Form Should render 1`] = ` > Upload file -
+ +
+ +
+

+ Drag and drop a file here or click +

+ +
+
+
+ +
- -
-

- Drag and drop a file here or click -

- -
+ Sign Out + + +
-
-
- -
-
- +
From 30408840e9f131911a2a1fca5387fd5e64524852 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 16:21:42 -0800 Subject: [PATCH 46/64] Fix waitFor in some tests --- src/components/App/App.test.js | 14 ++++---- src/components/contexts/UserContext.test.jsx | 38 ++++++++------------ 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 1068b72..0cb2b76 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -13,8 +13,6 @@ const renderRoute = async (route) => { const { container } = render(); if (screen.queryByText(LOADING_STATUS)) { await waitForElementToBeRemoved(() => screen.getByText(LOADING_STATUS)); - } else { - await waitFor(() => {}); } return container; }; @@ -24,48 +22,48 @@ describe("App", () => { it("Route / unauthenticated", async () => { setToken(null); const container = await renderRoute("/"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); + expect(container).toMatchSnapshot(); cleanup(); }); it("Route /signup unauthenticated", async () => { setToken(null); const container = await renderRoute("/signup"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign up"); + expect(container).toMatchSnapshot(); cleanup(); }); it("Route /home unauthenticated", async () => { setToken(null); const container = await renderRoute("/home"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); + expect(container).toMatchSnapshot(); cleanup(); }); it("Route / authenticated", async () => { setToken(TEST_TOKEN); const container = await renderRoute("/"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + expect(container).toMatchSnapshot(); cleanup(); }); it("Route /signup authenticated", async () => { setToken(TEST_TOKEN); const container = await renderRoute("/signup"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + expect(container).toMatchSnapshot(); cleanup(); }); it("Route /home authenticated", async () => { setToken(TEST_TOKEN); const container = await renderRoute("/home"); - expect(container).toMatchSnapshot(); expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); + expect(container).toMatchSnapshot(); cleanup(); }); diff --git a/src/components/contexts/UserContext.test.jsx b/src/components/contexts/UserContext.test.jsx index 37e26c3..6e8193a 100644 --- a/src/components/contexts/UserContext.test.jsx +++ b/src/components/contexts/UserContext.test.jsx @@ -55,19 +55,15 @@ describe("UseContext", () => { it("No error sign up", async () => { fireEvent.click(screen.getByTestId("signUp")); - await waitFor(() => { - expect(screen.getByTestId("error").innerHTML).toEqual(""); - expect(screen.getByTestId("fetching").innerHTML).toEqual("false"); - }); + await waitFor(() => expect(screen.getByTestId("fetching").innerHTML).toEqual("false")); + expect(screen.getByTestId("error").innerHTML).toEqual(""); }); it("Handle server error", async () => { auth.setSignUpResponse({ message: "SERVER-ERROR", error: "ERR" }); fireEvent.click(screen.getByTestId("signUp")); - await waitFor(() => { - expect(screen.getByTestId("error").innerHTML).toEqual("SERVER-ERROR"); - expect(screen.getByTestId("fetching").innerHTML).toEqual("false"); - }); + await waitFor(() => expect(screen.getByTestId("fetching").innerHTML).toEqual("false")); + expect(screen.getByTestId("error").innerHTML).toEqual("SERVER-ERROR"); auth.setSignUpResponse({}); }); }); @@ -116,26 +112,22 @@ describe("UseContext", () => { }); it("No error sign in", async () => { + const TOKEN_STRING = JSON.stringify(TEST_TOKEN); auth.setSignInResponse(TEST_TOKEN); fireEvent.click(screen.getByTestId("signIn")); - await waitFor(() => { - const TOKEN_STRING = JSON.stringify(TEST_TOKEN); - expect(screen.getByTestId("error").innerHTML).toEqual(""); - expect(screen.getByTestId("fetching").innerHTML).toEqual("false"); - expect(screen.getByTestId("token").innerHTML).toEqual(TOKEN_STRING); - if (!sessionStorage) return; - expect(sessionStorage.getItem("token")).toEqual(TOKEN_STRING); - sessionStorage.removeItem("token"); - }); - }); + await waitFor(() => expect(screen.getByTestId("fetching").innerHTML).toEqual("false")); + expect(screen.getByTestId("error").innerHTML).toEqual(""); + expect(screen.getByTestId("token").innerHTML).toEqual(TOKEN_STRING); + if (!sessionStorage) return; + expect(sessionStorage.getItem("token")).toEqual(TOKEN_STRING); + sessionStorage.removeItem("token"); + }); it("Handle server error", async () => { auth.setSignInResponse({ message: "SERVER-ERROR", error: "ERR" }); fireEvent.click(screen.getByTestId("signIn")); - await waitFor(() => { - expect(screen.getByTestId("error").innerHTML).toEqual("SERVER-ERROR"); - expect(screen.getByTestId("fetching").innerHTML).toEqual("false"); - }); + await waitFor(() => expect(screen.getByTestId("fetching").innerHTML).toEqual("false")); + expect(screen.getByTestId("error").innerHTML).toEqual("SERVER-ERROR"); auth.setSignUpResponse({}); }); }); @@ -157,7 +149,7 @@ describe("UseContext", () => { render(); auth.setSignInResponse(TEST_TOKEN); fireEvent.click(screen.getByTestId("signIn")); - await waitFor(() => {}); + await waitFor(() => expect(screen.getByTestId("fetching").innerHTML).toEqual("false")); }); afterEach(() => { From 8546234b4cf25eeb0fc0a6e6aab3dd15d20083d3 Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 16:22:13 -0800 Subject: [PATCH 47/64] File upload is done at 100 --- src/components/ModalProgressBar/index.jsx | 2 +- src/services/uploadFile.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ModalProgressBar/index.jsx b/src/components/ModalProgressBar/index.jsx index 4d79c15..3b861ea 100644 --- a/src/components/ModalProgressBar/index.jsx +++ b/src/components/ModalProgressBar/index.jsx @@ -33,7 +33,7 @@ const ModalProgressBar = ({ onCancel, uploading, progress, status }) => { {status &&

{status}

} diff --git a/src/services/uploadFile.js b/src/services/uploadFile.js index 5f0da86..81b6ed4 100644 --- a/src/services/uploadFile.js +++ b/src/services/uploadFile.js @@ -20,7 +20,7 @@ export const uploadFile = (file, onProgress, cancelToken) => { options = { ...options, onUploadProgress: (event) => { - onProgress(Math.floor((event.loaded / event.total) * 100)); + onProgress(Math.min(99, Math.floor((event.loaded / event.total) * 100))); } } } From 1ed43fa2a035416c5e4ce9755970de56e4fadf4a Mon Sep 17 00:00:00 2001 From: jwu-fisker Date: Thu, 7 Jan 2021 16:50:30 -0800 Subject: [PATCH 48/64] Add file upload tests --- src/components/contexts/FileUploadContext.jsx | 42 +++++++------ .../contexts/FileUploadContext.test.jsx | 61 +++++++++++++++++++ src/services/__mocks__/uploadFile.js | 29 +++++++++ src/utils/delay.js | 8 +++ 4 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 src/components/contexts/FileUploadContext.test.jsx create mode 100644 src/services/__mocks__/uploadFile.js create mode 100644 src/utils/delay.js diff --git a/src/components/contexts/FileUploadContext.jsx b/src/components/contexts/FileUploadContext.jsx index 046336a..acb70b1 100644 --- a/src/components/contexts/FileUploadContext.jsx +++ b/src/components/contexts/FileUploadContext.jsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from "react"; +import React, { useContext, useState } from "react"; import { uploadFile, getCancelToken } from "../../services/uploadFile"; const FileUploadContext = React.createContext(); @@ -10,32 +10,40 @@ export const FileUploadProvider = ({ children }) => { const [status, setStatus] = useState(null); const [cancelUpload, setCancelUpload] = useState(null); - const cancel = async () => { - console.log(`cancel`); - if (cancelUpload) cancelUpload.cancel(); + const done = () => { setCancelUpload(null); setUploading(false); + setProgress(0); + }; + + const cancel = async () => { + if (cancelUpload && progress < 100) { + cancelUpload.cancel(); + setStatus("Upload cancelled"); + } + done(); }; 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 { + if (!files || files.length === 0) throw new Error("No file provided"); + + const file = files[0].file; + const filename = file.name; + + setUploading(true); + setProgress(0); + setStatus(`Uploading ${filename}`); + setCancelUpload(getCancelToken()); + const result = await uploadFile(file, setProgress, cancelUpload); - console.log(result); - setStatus(`Uploaded ${filename}`); + const url = ((result && result.url) ? result.url : "No URL available"); + setStatus(`Uploaded ${filename}\n${url}`); setCancelUpload(null); - setProgress(101); + setProgress(100); } catch (e) { - setStatus(`Error occured ${e.message}`); + setStatus(`Error occured: ${e.message}`); } }; diff --git a/src/components/contexts/FileUploadContext.test.jsx b/src/components/contexts/FileUploadContext.test.jsx new file mode 100644 index 0000000..3e8e8ef --- /dev/null +++ b/src/components/contexts/FileUploadContext.test.jsx @@ -0,0 +1,61 @@ +jest.mock("../../services/uploadFile"); + +import {uploadFile, getCancelToken, setUploadFileResponse, setUploadFileDelay, getIssuedCancelToken } from "../../services/uploadFile" +import { FileUploadProvider, useFileUploadContext } from "../Contexts/FileUploadContext"; +import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" + +describe("FileUploadContext", () => { + + beforeEach(() => { + const TestComp = () => { + const { progress, uploading, status, upload, cancel } = useFileUploadContext(); + return ( + <> +
{uploading.toString()}
+
{progress.toString()}
+
{status}
+