diff --git a/client/package-lock.json b/client/package-lock.json index cb8b635..7180e55 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -936,22 +936,33 @@ "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" }, + "@hapi/formula": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-1.2.0.tgz", + "integrity": "sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA==" + }, "@hapi/hoek": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.2.4.tgz", - "integrity": "sha512-Ze5SDNt325yZvNO7s5C4fXDscjJ6dcqLFXJQ/M7dZRQCewuDj2iDUuBi6jLQt+APbW9RjjVEvLr35FXuOEqjow==" + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.2.5.tgz", + "integrity": "sha512-rmGFzok1zR3xZKd5m3ihWdqafXFxvPHoQ/78+AG5URKbEbJiwBBfRgzbu+07W5f3+07JRshw6QqGbVmCp8ntig==" }, "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-16.1.4.tgz", + "integrity": "sha512-m7ctezhxjob+dSpXnCNlgAj6rrEpdSsaWu3GWL3g1AybQCU36mlAo9IwGFJwIxD+oHgdO6mYyviYlaejX+qN6g==", "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" + "@hapi/address": "^2.1.2", + "@hapi/formula": "^1.2.0", + "@hapi/hoek": "^8.2.4", + "@hapi/pinpoint": "^1.0.2", + "@hapi/topo": "^3.1.3" } }, + "@hapi/pinpoint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-1.0.2.tgz", + "integrity": "sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ==" + }, "@hapi/topo": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.4.tgz", @@ -13114,6 +13125,17 @@ "workbox-window": "^4.3.1" }, "dependencies": { + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" + } + }, "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", diff --git a/client/package.json b/client/package.json index ccc7d9a..ca9e137 100644 --- a/client/package.json +++ b/client/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@hapi/joi": "^16.1.4", "babel-eslint": "^9.0.0", "prop-types": "^15.7.2", "react": "^16.9.0", diff --git a/client/src/components/App/index.js b/client/src/components/App/index.js index ae120cf..ffd664f 100644 --- a/client/src/components/App/index.js +++ b/client/src/components/App/index.js @@ -1,16 +1,36 @@ +/* eslint-disable react/no-unused-state */ import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; -import Error404 from '../utils/Error404/index'; -import './style.css'; + +import Login from '../pages/Login/index'; +import Error404 from '../pages/Error404/index'; import Home from '../home'; +import './style.css'; + +export default class App extends React.Component { + state = { + tableNumber: null, + }; + + updateTableNumber = (tableNumber, redirect) => { + this.setState({ tableNumber }, () => redirect('/')); + }; -export default () => { - return ( - - - - - - - ); -}; + render() { + return ( + + + ( + + )} + /> + + + + + ); + } +} diff --git a/client/src/components/utils/Error404/index.js b/client/src/components/pages/Error404/index.js similarity index 90% rename from client/src/components/utils/Error404/index.js rename to client/src/components/pages/Error404/index.js index 141c2d9..fa3be39 100644 --- a/client/src/components/utils/Error404/index.js +++ b/client/src/components/pages/Error404/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import error404 from '../../../assets/images/error.jpg'; -import Button from '../Button/index'; +import Button from '../../utils/Button/index'; import './style.css'; const Error404 = () => { diff --git a/client/src/components/utils/Error404/style.css b/client/src/components/pages/Error404/style.css similarity index 100% rename from client/src/components/utils/Error404/style.css rename to client/src/components/pages/Error404/style.css diff --git a/client/src/components/pages/Login/index.js b/client/src/components/pages/Login/index.js new file mode 100644 index 0000000..a76948a --- /dev/null +++ b/client/src/components/pages/Login/index.js @@ -0,0 +1,99 @@ +import React from 'react'; +import propTypes from 'prop-types'; +import logInSchema from '../../../validation/login'; +import Button from '../../utils/Button/index'; +import background from '../../../assets/images/login.background.png'; +import waiter from '../../../assets/images/waiter.png'; +import './style.css'; + +export default class Login extends React.Component { + state = { + tableNumber: '', + secret: '', + err: '', + }; + + setTableNumber = e => { + this.setState({ tableNumber: e.target.value }); + }; + + setSecret = e => { + this.setState({ secret: e.target.value }); + }; + + handleSubmit = e => { + e.preventDefault(); + const { tableNumber, secret } = this.state; + const { history, updateTableNumber } = this.props; + return logInSchema + .validateAsync({ tableNumber, secret }) + .then(() => { + return fetch('/api/v1/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + tableNumber, + secret, + }), + }); + }) + .then(res => { + if (res.status === 200) { + return updateTableNumber(tableNumber, history.push); + } + return this.setState({ err: 'Incorrect Table Number or Secret' }); + }) + .catch(err => { + if (err.details) { + if (err.details[0].message) { + this.setState({ err: err.details[0].message }); + } + } else { + this.setState({ err: 'Internal Server Error' }); + } + }); + }; + + render() { + const { tableNumber, secret, err } = this.state; + return ( +
+ backgroundImage +

HOTMEAL

+ waiterImage +
+ +
+ +
+ +
+

{err}

+
+ ); + } +} + +Login.propTypes = { + history: propTypes.objectOf(propTypes.any).isRequired, + updateTableNumber: propTypes.func.isRequired, +}; diff --git a/client/src/components/pages/Login/style.css b/client/src/components/pages/Login/style.css new file mode 100644 index 0000000..433f5b7 --- /dev/null +++ b/client/src/components/pages/Login/style.css @@ -0,0 +1,88 @@ +.login__background--image { + position: relative; + width: 100%; + height: 98vh; +} + +.login__waiter-image { + position: absolute; + width: 23vw; + height: 10vh; + left: 9rem; + top: 15.5rem; + box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.3); +} + +.login__title { + position: absolute; + left: 7.5rem; + top: 10rem; + font-family: Creepster; + font-style: normal; + font-weight: normal; + font-size: 2.6rem; + color: #FFFFFF; +} + +input { + position: absolute; + left: 4rem; + width: 38vw; + height: 2vh; + background-color: #21232F; + border: none; + color:#FFFFFF; + font: 1.2rem Roboto; +} + +::placeholder { + font-family: Roboto; + font-size: 1.1rem; + font-weight: 300; + color: #FFFFFF; +} + +.login__table-number { + top: 24.1rem; +} + +.login__secret-number { + top: 28.2rem; +} + +hr { + position: absolute; + width: 239px; + height: 0px; + left: 4rem; + border: 1px solid #FF9636; +} + +.login__first-line { + top: 25.5rem; +} + +.login__second-line { + top: 29.6rem; +} + +.login__err-message { + position: absolute; + top: 29.4rem; + left: 10%; + font-size: 1.3rem; + color: #ED1C24; + margin: 1.7rem auto; + text-align: center; + width: 80%; +} + +.login__button { + position: absolute; + width: 66vw; + height: 6vh; + left: 3.9rem; + top: 34.4rem; + font-size: 1.5rem; + box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.25); +} \ No newline at end of file diff --git a/client/src/validation/login.js b/client/src/validation/login.js new file mode 100644 index 0000000..80e7fc4 --- /dev/null +++ b/client/src/validation/login.js @@ -0,0 +1,10 @@ +import Joi from '@hapi/joi'; + +const logInSchema = Joi.object().keys({ + tableNumber: Joi.number() + .required() + .label('Table Number'), + secret: Joi.string().required(), +}); + +export default logInSchema;