Skip to content

Commit 792b381

Browse files
committed
Setting up our React app
1 parent 34b80c3 commit 792b381

File tree

8 files changed

+291
-12
lines changed

8 files changed

+291
-12
lines changed

src/Routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { Route, Switch } from "react-router-dom";
33
import AppliedRoute from "./components/AppliedRoute";
44
import Home from "./containers/Home";
55
import Login from "./containers/Login";
6+
import Signup from "./containers/Signup";
67
import NotFound from "./containers/NotFound";
78

89
export default function Routes({ appProps }) {
910
return (
1011
<Switch>
1112
<AppliedRoute path="/" exact component={Home} appProps={appProps} />
1213
<AppliedRoute path="/login" exact component={Login} appProps={appProps} />
14+
<AppliedRoute path="/signup" exact component={Signup} appProps={appProps} />
1315
{ /* Finally, catch all unmatched routes */ }
1416
<Route component={NotFound} />
1517
</Switch>

src/components/LoaderButton.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.LoaderButton .spinning.glyphicon {
2+
margin-right: 7px;
3+
top: 2px;
4+
animation: spin 1s infinite linear;
5+
}
6+
@keyframes spin {
7+
from { transform: scale(1) rotate(0deg); }
8+
to { transform: scale(1) rotate(360deg); }
9+
}

src/components/LoaderButton.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { Button, Glyphicon } from "react-bootstrap";
3+
import "./LoaderButton.css";
4+
5+
export default function LoaderButton({
6+
isLoading,
7+
className = "",
8+
disabled = false,
9+
...props
10+
}) {
11+
return (
12+
<Button
13+
className={`LoaderButton ${className}`}
14+
disabled={disabled || isLoading}
15+
{...props}
16+
>
17+
{isLoading && <Glyphicon glyph="refresh" className="spinning" />}
18+
{props.children}
19+
</Button>
20+
);
21+
}

src/containers/Login.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
import React, { useState } from "react";
22
import { Auth } from "aws-amplify";
3-
import { Button, FormGroup, FormControl, ControlLabel } from "react-bootstrap";
3+
import { FormGroup, FormControl, ControlLabel } from "react-bootstrap";
4+
import LoaderButton from "../components/LoaderButton";
5+
import { useFormFields } from "../libs/hooksLib";
46
import "./Login.css";
57

68
export default function Login(props) {
7-
const [email, setEmail] = useState("");
8-
const [password, setPassword] = useState("");
9+
const [isLoading, setIsLoading] = useState(false);
10+
const [fields, handleFieldChange] = useFormFields({
11+
email: "",
12+
password: ""
13+
});
914

1015
function validateForm() {
11-
return email.length > 0 && password.length > 0;
16+
return fields.email.length > 0 && fields.password.length > 0;
1217
}
1318

1419
async function handleSubmit(event) {
1520
event.preventDefault();
1621

22+
setIsLoading(true);
23+
1724
try {
18-
await Auth.signIn(email, password);
25+
await Auth.signIn(fields.email, fields.password);
1926
props.userHasAuthenticated(true);
20-
props.history.push("/");
2127
} catch (e) {
2228
alert(e.message);
29+
setIsLoading(false);
2330
}
2431
}
2532

@@ -31,21 +38,27 @@ export default function Login(props) {
3138
<FormControl
3239
autoFocus
3340
type="email"
34-
value={email}
35-
onChange={e => setEmail(e.target.value)}
41+
value={fields.email}
42+
onChange={handleFieldChange}
3643
/>
3744
</FormGroup>
3845
<FormGroup controlId="password" bsSize="large">
3946
<ControlLabel>Password</ControlLabel>
4047
<FormControl
41-
value={password}
42-
onChange={e => setPassword(e.target.value)}
4348
type="password"
49+
value={fields.password}
50+
onChange={handleFieldChange}
4451
/>
4552
</FormGroup>
46-
<Button block bsSize="large" disabled={!validateForm()} type="submit">
53+
<LoaderButton
54+
block
55+
type="submit"
56+
bsSize="large"
57+
isLoading={isLoading}
58+
disabled={!validateForm()}
59+
>
4760
Login
48-
</Button>
61+
</LoaderButton>
4962
</form>
5063
</div>
5164
);

src/containers/NewNote.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React, { useRef, useState } from "react";
2+
import { FormGroup, FormControl, ControlLabel } from "react-bootstrap";
3+
import LoaderButton from "../components/LoaderButton";
4+
import config from "../config";
5+
import "./NewNote.css";
6+
7+
export default function NewNote(props) {
8+
const file = useRef(null);
9+
const [content, setContent] = useState("");
10+
const [isLoading, setIsLoading] = useState(false);
11+
12+
function validateForm() {
13+
return content.length > 0;
14+
}
15+
16+
function handleFileChange(event) {
17+
file.current = event.target.files[0];
18+
}
19+
20+
async function handleSubmit(event) {
21+
event.preventDefault();
22+
23+
if (file.current && file.current.size > config.MAX_ATTACHMENT_SIZE) {
24+
alert(
25+
`Please pick a file smaller than ${config.MAX_ATTACHMENT_SIZE /
26+
1000000} MB.`
27+
);
28+
return;
29+
}
30+
31+
setIsLoading(true);
32+
}
33+
34+
return (
35+
<div className="NewNote">
36+
<form onSubmit={handleSubmit}>
37+
<FormGroup controlId="content">
38+
<FormControl
39+
value={content}
40+
componentClass="textarea"
41+
onChange={e => setContent(e.target.value)}
42+
/>
43+
</FormGroup>
44+
<FormGroup controlId="file">
45+
<ControlLabel>Attachment</ControlLabel>
46+
<FormControl onChange={handleFileChange} type="file" />
47+
</FormGroup>
48+
<LoaderButton
49+
block
50+
text="Create"
51+
type="submit"
52+
bsSize="large"
53+
bsStyle="primary"
54+
isLoading={isLoading}
55+
loadingText="Creating…"
56+
disabled={!validateForm()}
57+
/>
58+
</form>
59+
</div>
60+
);
61+
}

src/containers/Signup.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@media all and (min-width: 480px) {
2+
.Signup {
3+
padding: 60px 0;
4+
}
5+
6+
.Signup form {
7+
margin: 0 auto;
8+
max-width: 320px;
9+
}
10+
}
11+
12+
.Signup form span.help-block {
13+
font-size: 14px;
14+
padding-bottom: 10px;
15+
color: #999;
16+
}

src/containers/Signup.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React, { useState } from "react";
2+
import { Auth } from "aws-amplify";
3+
import {
4+
HelpBlock,
5+
FormGroup,
6+
FormControl,
7+
ControlLabel
8+
} from "react-bootstrap";
9+
import LoaderButton from "../components/LoaderButton";
10+
import { useFormFields } from "../libs/hooksLib";
11+
import "./Signup.css";
12+
13+
export default function Signup(props) {
14+
const [fields, handleFieldChange] = useFormFields({
15+
email: "",
16+
password: "",
17+
confirmPassword: "",
18+
confirmationCode: ""
19+
});
20+
const [newUser, setNewUser] = useState(null);
21+
const [isLoading, setIsLoading] = useState(false);
22+
23+
function validateForm() {
24+
return (
25+
fields.email.length > 0 &&
26+
fields.password.length > 0 &&
27+
fields.password === fields.confirmPassword
28+
);
29+
}
30+
31+
function validateConfirmationForm() {
32+
return fields.confirmationCode.length > 0;
33+
}
34+
35+
async function handleSubmit(event) {
36+
event.preventDefault();
37+
38+
setIsLoading(true);
39+
40+
try {
41+
const newUser = await Auth.signUp({
42+
username: fields.email,
43+
password: fields.password
44+
});
45+
setIsLoading(false);
46+
setNewUser(newUser);
47+
} catch (e) {
48+
alert(e.message);
49+
setIsLoading(false);
50+
}
51+
}
52+
53+
async function handleConfirmationSubmit(event) {
54+
event.preventDefault();
55+
56+
setIsLoading(true);
57+
58+
try {
59+
await Auth.confirmSignUp(fields.email, fields.confirmationCode);
60+
await Auth.signIn(fields.email, fields.password);
61+
62+
props.userHasAuthenticated(true);
63+
props.history.push("/");
64+
} catch (e) {
65+
alert(e.message);
66+
setIsLoading(false);
67+
}
68+
}
69+
70+
function renderConfirmationForm() {
71+
return (
72+
<form onSubmit={handleConfirmationSubmit}>
73+
<FormGroup controlId="confirmationCode" bsSize="large">
74+
<ControlLabel>Confirmation Code</ControlLabel>
75+
<FormControl
76+
autoFocus
77+
type="tel"
78+
onChange={handleFieldChange}
79+
value={fields.confirmationCode}
80+
/>
81+
<HelpBlock>Please check your email for the code.</HelpBlock>
82+
</FormGroup>
83+
<LoaderButton
84+
block
85+
type="submit"
86+
bsSize="large"
87+
isLoading={isLoading}
88+
disabled={!validateConfirmationForm()}
89+
>
90+
Verify
91+
</LoaderButton>
92+
</form>
93+
);
94+
}
95+
96+
function renderForm() {
97+
return (
98+
<form onSubmit={handleSubmit}>
99+
<FormGroup controlId="email" bsSize="large">
100+
<ControlLabel>Email</ControlLabel>
101+
<FormControl
102+
autoFocus
103+
type="email"
104+
value={fields.email}
105+
onChange={handleFieldChange}
106+
/>
107+
</FormGroup>
108+
<FormGroup controlId="password" bsSize="large">
109+
<ControlLabel>Password</ControlLabel>
110+
<FormControl
111+
type="password"
112+
value={fields.password}
113+
onChange={handleFieldChange}
114+
/>
115+
</FormGroup>
116+
<FormGroup controlId="confirmPassword" bsSize="large">
117+
<ControlLabel>Confirm Password</ControlLabel>
118+
<FormControl
119+
type="password"
120+
onChange={handleFieldChange}
121+
value={fields.confirmPassword}
122+
/>
123+
</FormGroup>
124+
<LoaderButton
125+
block
126+
type="submit"
127+
bsSize="large"
128+
isLoading={isLoading}
129+
disabled={!validateForm()}
130+
>
131+
Signup
132+
</LoaderButton>
133+
</form>
134+
);
135+
}
136+
137+
return (
138+
<div className="Signup">
139+
{newUser === null ? renderForm() : renderConfirmationForm()}
140+
</div>
141+
);
142+
}

src/libs/hooksLib.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useState } from "react";
2+
3+
export function useFormFields(initialState) {
4+
const [fields, setValues] = useState(initialState);
5+
6+
return [
7+
fields,
8+
function(event) {
9+
setValues({
10+
...fields,
11+
[event.target.id]: event.target.value
12+
});
13+
}
14+
];
15+
}

0 commit comments

Comments
 (0)