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 (
+
+
+
HOTMEAL
+
+
+
{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;