diff --git a/.babelrc b/.babelrc index e60d303..da1fef0 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,7 @@ { "presets": ["@babel/preset-env", "@babel/preset-react"], - "plugins": ["@babel/plugin-proposal-class-properties"] + "plugins": [ + "@babel/plugin-proposal-class-properties", + "@babel/plugin-transform-runtime" + ] } diff --git a/package-lock.json b/package-lock.json index ce09823..fe3e4c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -693,6 +693,18 @@ "regenerator-transform": "^0.13.3" } }, + "@babel/plugin-transform-runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + } + }, "@babel/plugin-transform-shorthand-properties": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", @@ -1418,6 +1430,15 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -2851,19 +2872,6 @@ "abab": "^2.0.0", "whatwg-mimetype": "^2.2.0", "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", - "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } } }, "date-now": { @@ -4243,7 +4251,6 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", - "dev": true, "requires": { "debug": "=3.1.0" }, @@ -4252,7 +4259,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -5722,8 +5728,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-builtin-module": { "version": "1.0.0", @@ -6684,6 +6689,68 @@ "jest-mock": "^23.2.0", "jest-util": "^23.4.0", "jsdom": "^11.5.1" + }, + "dependencies": { + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } } }, "jest-environment-node": { @@ -7459,43 +7526,49 @@ "dev": true }, "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-13.1.0.tgz", + "integrity": "sha512-C2Kp0qNuopw0smXFaHeayvharqF3kkcNqlcIlSX71+3XrsOFwkEPLt/9f5JksMmaul2JZYIQuY+WTpqHpQQcLg==", "dev": true, "requires": { "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", + "acorn": "^6.0.4", + "acorn-globals": "^4.3.0", "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", + "cssom": "^0.3.4", + "cssstyle": "^1.1.1", + "data-urls": "^1.1.0", "domexception": "^1.0.1", - "escodegen": "^1.9.1", + "escodegen": "^1.11.0", "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", + "nwsapi": "^2.0.9", + "parse5": "5.1.0", "pn": "^1.1.0", - "request": "^2.87.0", + "request": "^2.88.0", "request-promise-native": "^1.0.5", - "sax": "^1.2.4", + "saxes": "^3.1.4", "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", + "tough-cookie": "^2.5.0", "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.0.1", "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^6.1.2", "xml-name-validator": "^3.0.0" }, "dependencies": { + "acorn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", + "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==", + "dev": true + }, "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", "dev": true } } @@ -7571,6 +7644,11 @@ "array-includes": "^3.0.3" } }, + "jwt-decode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=" + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -9827,6 +9905,15 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "saxes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.5.tgz", + "integrity": "sha512-2mgiX2VOarcQv8G40WdJ5QJniYdsPr0yGedkd98PqApodsS9DG29qyHl/X65OILm7Bapd1/zUUvTHVZwNLhXvQ==", + "dev": true, + "requires": { + "xmlchars": "^1.3.1" + } + }, "scheduler": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", @@ -11313,6 +11400,17 @@ "browser-process-hrtime": "^0.1.2" } }, + "w3c-xmlserializer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.0.1.tgz", + "integrity": "sha512-XZGI1OH/OLQr/NaJhhPmzhngwcAnZDLytsvXnRmlYeRkmbb0I7sqFFA22erq4WQR0sUu17ZSQOAV9mFwCqKRNg==", + "dev": true, + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, "walker": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", @@ -11644,9 +11742,9 @@ "dev": true }, "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", @@ -11758,9 +11856,9 @@ } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", + "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", "dev": true, "requires": { "async-limiter": "~1.0.0" @@ -11772,6 +11870,12 @@ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, + "xmlchars": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz", + "integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==", + "dev": true + }, "xregexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", diff --git a/package.json b/package.json index 813a831..4b4ccff 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "heroku-postbuild": "npm run build", "dev": "webpack-dev-server --open --config webpack.config.dev.js", "dev:hot": "npm run dev -- --hot", - "test": "jest --config=jest.config.json", + "test": "jest --config=jest.config.json --env=jsdom", "test:watch": "npm test -- --watch", "coverage": "npm run test -- --coverage", "coveralls": "npm run coverage && cat ./coverage/lcov.info | coveralls" @@ -27,7 +27,9 @@ }, "homepage": "https://github.com/akhilome/kiakiafood#readme", "dependencies": { + "axios": "^0.18.0", "express": "^4.16.4", + "jwt-decode": "^2.2.0", "prop-types": "^15.6.2", "react": "^16.7.0", "react-dom": "^16.7.0", @@ -41,6 +43,7 @@ "@babel/cli": "^7.2.3", "@babel/core": "^7.2.2", "@babel/plugin-proposal-class-properties": "^7.2.3", + "@babel/plugin-transform-runtime": "^7.2.0", "@babel/preset-env": "^7.2.3", "@babel/preset-react": "^7.0.0", "babel-core": "^7.0.0-bridge.0", @@ -59,6 +62,7 @@ "eslint-plugin-react": "^7.12.3", "html-webpack-plugin": "^3.2.0", "jest": "^23.6.0", + "jsdom": "^13.1.0", "style-loader": "^0.23.1", "webpack": "^4.28.1", "webpack-cli": "^3.2.1", diff --git a/src/actions/index.js b/src/actions/index.js index e69de29..5a720ba 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -0,0 +1,46 @@ +import axios from '../services/axios'; +import actionTypes from './types'; +import { saveToken, getToken } from '../utils/localStorage'; +import jwt from '../utils/jwt'; + +export const startFetching = () => ({ type: actionTypes.START_FETCHING }); +export const stopFetching = (fetchSuccess = true, message = '') => ({ + type: actionTypes.STOP_FETCHING, + payload: { + error: !fetchSuccess, + message, + }, +}); + +export const signUpUser = userData => async (dispatch) => { + dispatch(startFetching()); + try { + const { status, user } = (await axios.post('/auth/signup', userData)).data; + if (status === 'success') saveToken(user.auth_token); + const { userName: name, userStatus: role } = jwt.decode(user.auth_token); + dispatch({ + type: actionTypes.SIGN_UP, + payload: { + name, + role, + }, + }); + return dispatch(stopFetching()); + } catch (error) { + return dispatch( + stopFetching(false, error.response ? error.response.data.message : 'something went wrong'), + ); + } +}; + +export const checkAuthStatus = () => { + try { + const { userName: name, userStatus: role } = jwt.decode(getToken()); + return { + type: actionTypes.CHECK_AUTH_STATUS, + payload: { name, role }, + }; + } catch (error) { + return { type: actionTypes.CHECK_AUTH_STATUS_FAIL }; + } +}; diff --git a/src/actions/types/index.js b/src/actions/types/index.js new file mode 100644 index 0000000..d089aa8 --- /dev/null +++ b/src/actions/types/index.js @@ -0,0 +1,8 @@ +export default { + SIGN_UP: 'SIGN_UP', + LOG_IN: 'LOG_IN', + START_FETCHING: 'START_FETCHING', + STOP_FETCHING: 'STOP_FETCHING', + CHECK_AUTH_STATUS: 'CHECK_AUTH_STATUS', + CHECK_AUTH_STATUS_FAIL: 'CHECK_AUTH_STATUS_FAIL', +}; diff --git a/src/components/App.jsx b/src/components/App.jsx index 48d19d6..3017aa4 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -1,20 +1,39 @@ import '../index.css'; -import React from 'react'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; +import propTypes from 'prop-types'; +import { checkAuthStatus } from '../actions'; import HomePage from './HomePage'; import LoginPage from './LoginPage'; -import SignupPage from './SignupPage'; +import Signup from './SignupPage'; import NotFoundPage from './NotFoundPage'; -const App = () => ( - - - - - - - - -); +export class App extends Component { + componentDidMount() { + const { checkAuthStatus: checkUserAuthStatus } = this.props; + checkUserAuthStatus(); + } -export default App; + render() { + return ( + + + + + + + + + ); + } +} + +App.propTypes = { + checkAuthStatus: propTypes.func.isRequired, +}; + +export default connect( + null, + { checkAuthStatus }, +)(App); diff --git a/src/components/HomePage.jsx b/src/components/HomePage.jsx index 3ab486c..5aaf9c9 100644 --- a/src/components/HomePage.jsx +++ b/src/components/HomePage.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { Link } from 'react-router-dom'; - import Nav from './Nav'; const HomePage = () => ( diff --git a/src/components/SignupPage.jsx b/src/components/SignupPage.jsx index 4e221ea..ce50f86 100644 --- a/src/components/SignupPage.jsx +++ b/src/components/SignupPage.jsx @@ -1,12 +1,126 @@ -import React from 'react'; +import React, { Component, Fragment } from 'react'; import { Link } from 'react-router-dom'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { signUpUser } from '../actions'; +import Nav from './Nav'; -const SignupPage = () => ( -
- This is the signup page -
- Go Home -
-); +export class SignupPage extends Component { + state = { + name: '', + email: '', + password: '', + confirmPassword: '', + adminSecret: '', + }; -export default SignupPage; + componentDidMount() { + const { isLoggedIn, fetching, history } = this.props; + if (!fetching && isLoggedIn) history.push('/menu'); + } + + onFormSubmit = async (e) => { + e.preventDefault(); + const { + name, email, password, confirmPassword, adminSecret, + } = this.state; + const { signUpUser: register } = this.props; + await register({ + name, + email, + password, + confirmPassword, + adminSecret, + }); + const { isLoggedIn, fetching, history } = this.props; + if (!fetching && isLoggedIn) history.push('/menu'); + }; + + render() { + const { + name, email, password, confirmPassword, adminSecret, + } = this.state; + return ( + +