login
parent
714dd8b919
commit
5b6fb4eb3e
|
@ -13,6 +13,7 @@
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"antd": "^5.4.2",
|
"antd": "^5.4.2",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-qr-scanner": "^1.0.0-alpha.11",
|
"react-qr-scanner": "^1.0.0-alpha.11",
|
||||||
|
@ -5635,6 +5636,25 @@
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/batch": {
|
"node_modules/batch": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||||
|
@ -5806,6 +5826,29 @@
|
||||||
"node-int64": "^0.4.0"
|
"node-int64": "^0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
|
@ -9239,6 +9282,25 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.2.4",
|
"version": "5.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
"@testing-library/react": "^13.4.0",
|
"@testing-library/react": "^13.4.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"antd": "^5.4.2",
|
"antd": "^5.4.2",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-qr-scanner": "^1.0.0-alpha.11",
|
"react-qr-scanner": "^1.0.0-alpha.11",
|
||||||
|
|
|
@ -29,15 +29,5 @@
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
55
src/App.css
55
src/App.css
|
@ -1,30 +1,3 @@
|
||||||
/*.App {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/*
|
|
||||||
.SideMenuAndPageContent {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
/*background-color: rgba(0, 0, 0, 0.05);*/ /*
|
|
||||||
min-height: 100vh;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* SideMenu */
|
|
||||||
/*.SideMenu {
|
|
||||||
height: 100vh;
|
|
||||||
/*background-color: #fff;*/ /*
|
|
||||||
} */
|
|
||||||
/*
|
|
||||||
.SideMenuVertical {
|
|
||||||
height: 100%;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.CompanyName {
|
.CompanyName {
|
||||||
padding: 12px 12px 0 12px;
|
padding: 12px 12px 0 12px;
|
||||||
color: #e67e22;
|
color: #e67e22;
|
||||||
|
@ -41,31 +14,3 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PageContent */
|
|
||||||
/*.PageContent {
|
|
||||||
padding: 12px;
|
|
||||||
width: 100%;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* Login */
|
|
||||||
.login {
|
|
||||||
position: fixed; /* Stay in place */
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%; /* Full width */
|
|
||||||
height: 100%; /* Full height */
|
|
||||||
overflow: auto; /* Enable scroll if needed */
|
|
||||||
background-color: rgb(0, 0, 0); /* Fallback color */
|
|
||||||
background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
|
|
||||||
padding-top: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-content {
|
|
||||||
background-color: #fefefe;
|
|
||||||
margin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: 80%; /* Could be more or less, depending on screen size */
|
|
||||||
padding: 24px 24px 0 24px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
45
src/App.js
45
src/App.js
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import "antd/dist/reset.css";
|
import "antd/dist/reset.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import PageContent from "./Components/PageContent";
|
import PageContent from "./Components/PageContent";
|
||||||
|
@ -6,20 +6,41 @@ import SideMenu from "./Components/SideMenu";
|
||||||
import Login from "./Pages/Login";
|
import Login from "./Pages/Login";
|
||||||
import { Layout } from "antd";
|
import { Layout } from "antd";
|
||||||
|
|
||||||
|
function useUserSession() {
|
||||||
|
const getUserSession = () => {
|
||||||
|
return JSON.parse(localStorage.getItem("session"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const [userSession, setUserSession] = useState(getUserSession());
|
||||||
|
|
||||||
|
const saveUserSession = (session) => {
|
||||||
|
setUserSession(session);
|
||||||
|
|
||||||
|
if (session === undefined) {
|
||||||
|
localStorage.removeItem("session");
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("session", JSON.stringify(session));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
setUserSession: saveUserSession,
|
||||||
|
userSession,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [loggedIn, setLoggedIn] = useState(false);
|
const { userSession, setUserSession } = useUserSession();
|
||||||
|
|
||||||
|
if (!userSession) {
|
||||||
|
return <Login setUserSession={setUserSession} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Layout style={{ minHeight: "100vh" }}>
|
||||||
{loggedIn ? (
|
<SideMenu setUserSession={setUserSession}></SideMenu>
|
||||||
<Layout style={{ minHeight: "100vh" }}>
|
<PageContent></PageContent>
|
||||||
<SideMenu setLoggedIn={setLoggedIn}></SideMenu>
|
</Layout>
|
||||||
<PageContent></PageContent>
|
|
||||||
</Layout>
|
|
||||||
) : (
|
|
||||||
<Login setLoggedIn={setLoggedIn} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { useEffect, useState } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
export default function SideMenu({ setLoggedIn }) {
|
export default function SideMenu({ setUserSession }) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [selectedKeys, setSelectedKeys] = useState("/");
|
const [selectedKeys, setSelectedKeys] = useState("/");
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ export default function SideMenu({ setLoggedIn }) {
|
||||||
{
|
{
|
||||||
label: "Logout",
|
label: "Logout",
|
||||||
icon: <LogoutOutlined />,
|
icon: <LogoutOutlined />,
|
||||||
onClick: () => setLoggedIn(false),
|
onClick: () => setUserSession(),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
@ -77,5 +77,5 @@ export default function SideMenu({ setLoggedIn }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SideMenu.propTypes = {
|
SideMenu.propTypes = {
|
||||||
setLoggedIn: PropTypes.func.isRequired,
|
setUserSession: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,60 @@
|
||||||
import { LockOutlined, LoginOutlined, UserOutlined } from "@ant-design/icons";
|
import { LockOutlined, LoginOutlined, UserOutlined } from "@ant-design/icons";
|
||||||
import { Button, Form, Input } from "antd";
|
import { Button, Form, Input, Modal } from "antd";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
import config from "../../constants";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Buffer } from "buffer";
|
||||||
|
|
||||||
|
export default function Login({ setUserSession }) {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
fetch(config.API_ADDRESS + "/user/auth/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: Buffer.from(password).toString("base64"),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(res.status);
|
||||||
|
})
|
||||||
|
.then((data) => setUserSession(data.Session))
|
||||||
|
.catch(console.error);
|
||||||
|
};
|
||||||
|
|
||||||
export default function Login({ setLoggedIn }) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="login">
|
<Modal
|
||||||
<Form className="login-content">
|
title="Login"
|
||||||
|
open={true}
|
||||||
|
closable={false}
|
||||||
|
centered
|
||||||
|
keyboard={false}
|
||||||
|
footer={
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
icon={<LoginOutlined />}
|
||||||
|
className="login-form-button"
|
||||||
|
onClick={() => handleSubmit()}
|
||||||
|
>
|
||||||
|
Log in
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form>
|
||||||
<Form.Item name="username">
|
<Form.Item name="username">
|
||||||
<Input
|
<Input
|
||||||
prefix={<UserOutlined className="site-form-item-icon" />}
|
prefix={<UserOutlined className="site-form-item-icon" />}
|
||||||
placeholder="Username"
|
placeholder="Username"
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
@ -26,25 +70,15 @@ export default function Login({ setLoggedIn }) {
|
||||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
htmlType="submit"
|
|
||||||
icon={<LoginOutlined />}
|
|
||||||
className="login-form-button"
|
|
||||||
onClick={() => setLoggedIn(true)}
|
|
||||||
>
|
|
||||||
Log in
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Login.propTypes = {
|
Login.propTypes = {
|
||||||
setLoggedIn: PropTypes.func.isRequired,
|
setUserSession: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
const config = {
|
||||||
|
API_ADDRESS: "http://localhost:8080/v1",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
Loading…
Reference in New Issue