Skip to content

Commit ea944df

Browse files
committed
First commit
1 parent c645e01 commit ea944df

File tree

12 files changed

+1617
-36
lines changed

12 files changed

+1617
-36
lines changed

.circleci/config.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
version: 2.1
3+
4+
orbs:
5+
node: circleci/[email protected]
6+
7+
jobs:
8+
build:
9+
executor:
10+
name: node/default
11+
tag: 'lts'
12+
steps:
13+
- checkout
14+
- add_ssh_keys:
15+
fingerprints:
16+
- "f6:f7:d9:cf:34:03:0e:97:c1:d4:f3:88:d4:26:8f:95"
17+
- node/install-yarn
18+
- node/install-packages:
19+
pkg-manager: yarn
20+
- run: openssl aes-256-cbc -d -pbkdf2 -in encrypt.ts.enc -out src/encrypt.ts -k $DECRYPT_KEY
21+
- run: CI=false yarn build
22+
- run: |
23+
tar Jcvf public.tar.xz public/
24+
ssh-keyscan -t rsa cloud.drjchn.com >> ~/.ssh/known_hosts
25+
scp public.tar.xz [email protected]:~
26+
ssh [email protected] < deploy.sh
27+
workflows:
28+
version: 2
29+
master_build:
30+
jobs:
31+
- build:
32+
filters:
33+
branches:
34+
only: master

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/node_modules
55
/.pnp
66
.pnp.js
7+
encrypt.ts
78

89
# testing
910
/coverage
@@ -17,6 +18,7 @@
1718
.env.development.local
1819
.env.test.local
1920
.env.production.local
21+
.idea/
2022

2123
npm-debug.log*
2224
yarn-debug.log*

deploy.sh

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
3+
tar xvf public.tar.xz
4+
sudo mv public /var/www/blood
5+
sudo chown -R www-data:www-data /var/www/blood

encrypt.ts.enc

192 Bytes
Binary file not shown.

package.json

+9
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,24 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"@ant-design/charts": "^1.1.1",
7+
"@ant-design/icons": "^4.6.2",
68
"@testing-library/jest-dom": "^5.11.4",
79
"@testing-library/react": "^11.1.0",
810
"@testing-library/user-event": "^12.1.10",
11+
"@types/crypto-js": "^4.0.1",
912
"@types/jest": "^26.0.15",
1013
"@types/node": "^12.0.0",
1114
"@types/react": "^17.0.0",
1215
"@types/react-dom": "^17.0.0",
16+
"@types/react-router-dom": "^5.1.7",
17+
"antd": "^4.15.1",
18+
"axios": "^0.21.1",
19+
"crypto-js": "^4.0.0",
20+
"dayjs": "^1.10.4",
1321
"react": "^17.0.2",
1422
"react-dom": "^17.0.2",
23+
"react-router-dom": "^5.2.0",
1524
"react-scripts": "4.0.3",
1625
"typescript": "^4.1.2",
1726
"web-vitals": "^1.0.1"

public/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
work correctly both with client-side routing and a non-root public URL.
2525
Learn how to configure a non-root public URL by running `npm run build`.
2626
-->
27-
<title>React App</title>
27+
<title>Blood Data</title>
2828
</head>
2929
<body>
3030
<noscript>You need to enable JavaScript to run this app.</noscript>

src/App.css

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import "~antd/dist/antd.css";
2+
13
.App {
24
text-align: center;
35
}

src/App.tsx

+39-22
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,43 @@
1-
import React from 'react';
2-
import logo from './logo.svg';
1+
import React, { FC } from 'react';
2+
import {
3+
BrowserRouter as Router,
4+
Switch,
5+
Route,
6+
Link,
7+
} from 'react-router-dom';
8+
import { Layout, Typography, Result, Button } from 'antd';
39
import './App.css';
10+
import LoginPage from './pages/Login';
11+
import TablePage from './pages/Table';
412

5-
function App() {
6-
return (
7-
<div className="App">
8-
<header className="App-header">
9-
<img src={logo} className="App-logo" alt="logo" />
10-
<p>
11-
Edit <code>src/App.tsx</code> and save to reload.
12-
</p>
13-
<a
14-
className="App-link"
15-
href="https://reactjs.org"
16-
target="_blank"
17-
rel="noopener noreferrer"
18-
>
19-
Learn React
20-
</a>
21-
</header>
22-
</div>
23-
);
24-
}
13+
const { Header, Content } = Layout;
14+
const { Title } = Typography;
2515

16+
const App: FC = () => (
17+
<div className="App">
18+
<Header style={{ textAlign: "left" }}>
19+
<Title style={{ color: "white", lineHeight: "2em" }} level={2}>Blood Data</Title>
20+
</Header>
21+
<Content style={{ padding: "2em" }}>
22+
<Router>
23+
<Switch>
24+
<Route path="/login">
25+
<LoginPage />
26+
</Route>
27+
<Route exact path="/">
28+
<TablePage />
29+
</Route>
30+
<Route path="*">
31+
<Result
32+
status="404"
33+
title="404 Not Found"
34+
subTitle="Sorry, the page you visited does not exist."
35+
extra={<Link to="/"><Button type="primary">Back Home</Button></Link>}
36+
/>
37+
</Route>
38+
</Switch>
39+
</Router>
40+
</Content>
41+
</div>
42+
);
2643
export default App;

src/pages/Login.tsx

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Form, Input, Button, message } from 'antd';
2+
import axios from 'axios';
3+
import React from 'react';
4+
import { Redirect } from 'react-router';
5+
6+
axios.defaults.withCredentials = true;
7+
8+
const layout = {
9+
labelCol: { span: 8 },
10+
wrapperCol: { span: 8 },
11+
};
12+
const tailLayout = {
13+
wrapperCol: { offset: 5, span: 8 },
14+
};
15+
16+
class LoginPage extends React.Component {
17+
state = {
18+
redirect: null,
19+
loading: false
20+
}
21+
22+
onFinish = (values: any): void => {
23+
const { username, password } = values;
24+
25+
this.setState({ loading: true });
26+
27+
axios.post("http://localhost:5000/api/login", {
28+
username,
29+
password
30+
}).then(response => {
31+
const { username, message: msg } = response.data;
32+
window.localStorage.setItem("username", username);
33+
message.success(msg);
34+
this.setState({ redirect: <Redirect to="/" />, loading: false });
35+
}).catch(err => {
36+
this.setState({ loading: false });
37+
if (err.response) {
38+
message.error(err.response.data.message);
39+
}
40+
else {
41+
message.error("Login Failed");
42+
}
43+
})
44+
}
45+
46+
onFinishFailed = (err: any): void => {
47+
message.error("Failed: ", err);
48+
}
49+
50+
render() {
51+
const { redirect, loading } = this.state;
52+
53+
if (window.localStorage.username) {
54+
this.setState({ redirect: <Redirect to="/" /> });
55+
}
56+
57+
return (
58+
<Form
59+
{...layout}
60+
name="Login"
61+
onFinish={this.onFinish}
62+
onFinishFailed={this.onFinishFailed}
63+
>
64+
{redirect}
65+
<Form.Item
66+
label="Username"
67+
name="username"
68+
rules={[{ required: true, message: "Please input username!" }]}
69+
>
70+
<Input />
71+
</Form.Item>
72+
<Form.Item
73+
label="Password"
74+
name="password"
75+
rules={[{ required: true, message: "Please input password!" }]}
76+
>
77+
<Input.Password />
78+
</Form.Item>
79+
<Form.Item {...tailLayout}>
80+
<Button type="primary" htmlType="submit" loading={loading}>Login</Button>
81+
</Form.Item>
82+
</Form>
83+
)
84+
}
85+
}
86+
87+
export default LoginPage;

0 commit comments

Comments
 (0)