Skip to content

Commit 1cb5fd8

Browse files
committed
event registration
1 parent 7e7f435 commit 1cb5fd8

File tree

13 files changed

+187
-39
lines changed

13 files changed

+187
-39
lines changed

client/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const anonRoutes = {
1414

1515
const authedRoutes = {
1616
left: [
17-
{ href: '/event', label: 'Event' },
17+
{ href: '/event', label: 'My Event' },
1818
{ href: '/create', label: 'Create' },
1919
],
2020
right: [

client/account/DeleteAccountModal.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import ModalWrapper from 'client/components/ModalWrapper';
3-
import { Modal, Button } from 'react-bootstrap';
3+
import { Modal, Button, Alert } from 'react-bootstrap';
44
import { post } from 'client/lib/requests';
55

66
interface Props {
@@ -10,6 +10,7 @@ interface Props {
1010

1111
function DeleteAccountModal({ isShowing, hideModal }: Props) {
1212
const [loading, setLoading] = React.useState(false);
13+
const [error, setError] = React.useState('');
1314

1415
const onDeleteAccount = async () => {
1516
setLoading(true);
@@ -18,7 +19,9 @@ function DeleteAccountModal({ isShowing, hideModal }: Props) {
1819
await post('/api/delete_account');
1920
} catch (e) {
2021
setLoading(false);
21-
throw e; //TODO messaging
22+
setError(e.message);
23+
24+
return;
2225
}
2326

2427
setLoading(false);
@@ -29,6 +32,7 @@ function DeleteAccountModal({ isShowing, hideModal }: Props) {
2932
const onHide = () => {
3033
if (loading) {
3134
return;
35+
'';
3236
}
3337

3438
hideModal();
@@ -38,11 +42,14 @@ function DeleteAccountModal({ isShowing, hideModal }: Props) {
3842
<ModalWrapper isShowing={isShowing} onHide={onHide}>
3943
<Modal.Header>Delete Account</Modal.Header>
4044
<Modal.Body>
41-
You sure you want to do this? No take backsies.
42-
<br />
43-
<br />
44-
Also, your account will automatically be deleted a week after your event
45-
ends.
45+
<p>
46+
You sure you want to do this? No take backsies.
47+
<br />
48+
<br />
49+
Also, your account will automatically be deleted a week after your
50+
event ends.
51+
</p>
52+
{error && <Alert variant="danger">{error}</Alert>}
4653
</Modal.Body>
4754
<Modal.Footer>
4855
<Button variant="secondary" onClick={hideModal}>

client/eventPage/JoinEventModal.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import * as React from 'react';
2+
import ModalWrapper from 'client/components/ModalWrapper';
3+
import { Modal, Button, Alert } from 'react-bootstrap';
4+
import { post } from 'client/lib/requests';
5+
import { Event, Role } from 'client/types';
6+
7+
interface Props {
8+
isShowing: boolean;
9+
hideModal(): void;
10+
event: Event;
11+
role: Role;
12+
}
13+
14+
function JoinEventModal({ isShowing, hideModal, event, role }: Props) {
15+
const [loading, setLoading] = React.useState(false);
16+
const [error, setError] = React.useState('');
17+
18+
const onRegister = async () => {
19+
setLoading(true);
20+
21+
try {
22+
await post('/api/events/register', { eventId: event._id, role });
23+
} catch (e) {
24+
setLoading(false);
25+
setError(e.message);
26+
27+
return;
28+
}
29+
30+
setLoading(false);
31+
};
32+
33+
const onHide = () => {
34+
if (loading) {
35+
return;
36+
'';
37+
}
38+
39+
hideModal();
40+
};
41+
42+
const location = [event.city, event.state].filter(s => !!s).join(', ');
43+
44+
return (
45+
<ModalWrapper isShowing={isShowing} onHide={onHide}>
46+
<Modal.Header>Join Event: {event.name}</Modal.Header>
47+
<Modal.Body>
48+
Do you want to join the event <strong>{event.name}</strong>
49+
{location && (
50+
<span>
51+
located in <em>{location}</em>
52+
</span>
53+
)}{' '}
54+
as a(n) {role}?{error && <Alert variant="danger">{error}</Alert>}
55+
</Modal.Body>
56+
<Modal.Footer>
57+
<Button variant="secondary" onClick={hideModal}>
58+
Cancel
59+
</Button>
60+
<Button variant="primary" onClick={onRegister}>
61+
Join
62+
</Button>
63+
</Modal.Footer>
64+
</ModalWrapper>
65+
);
66+
}
67+
68+
export default JoinEventModal;

client/eventPage/JoinForm.tsx

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import * as React from 'react';
2-
import { Form, Button } from 'react-bootstrap';
3-
import { Role, InputEvent } from 'client/types';
2+
import { Form, Button, Alert } from 'react-bootstrap';
3+
import { Role, InputEvent, Event } from 'client/types';
44
import { get } from 'client/lib/requests';
5+
import JoinEventModal from './JoinEventModal';
56

67
export default () => {
78
const [role, setRole] = React.useState<Role | ''>('');
89
const [code, setCode] = React.useState('');
910
const [loading, setLoading] = React.useState(false);
11+
const [event, setEvent] = React.useState<Event>('');
12+
const [showEventModal, setShowEventModal] = React.useState(false);
13+
const [error, setError] = React.useState('');
1014

1115
const capitalizedRole = role.slice(0, 1).toUpperCase() + role.slice(1);
1216

@@ -16,18 +20,46 @@ export default () => {
1620
} else if (role === 'mentor') {
1721
setRole('attendee');
1822
}
23+
setCode('');
1924
};
2025

2126
const findEvent = async (e: React.FormEvent) => {
2227
e.preventDefault();
2328
setLoading(true);
24-
const res = await get(`/api/events/find?code=${code}`);
25-
console.log(res);
29+
30+
let foundEvent;
31+
32+
try {
33+
const res = await get(`/api/events/find?code=${code}&role=${role}`);
34+
const body = await res.json();
35+
36+
if (!res.ok) {
37+
throw new Error(body.message);
38+
}
39+
40+
foundEvent = body;
41+
} catch (e) {
42+
setLoading(false);
43+
setError(e.message);
44+
45+
return;
46+
}
47+
2648
setLoading(false);
49+
setEvent(foundEvent);
50+
setShowEventModal(true);
2751
};
2852

2953
return (
3054
<div className="join-form">
55+
{showEventModal && (
56+
<JoinEventModal
57+
isShowing={showEventModal}
58+
hideModal={() => setShowEventModal(false)}
59+
event={event}
60+
role={role}
61+
/>
62+
)}
3163
{role ? (
3264
<Form>
3365
<Form.Group>
@@ -39,7 +71,10 @@ export default () => {
3971
required
4072
type="text"
4173
placeholder={`Enter ${capitalizedRole} Code`}
42-
onChange={(e: InputEvent) => setCode(e.currentTarget.value)}
74+
onChange={(e: InputEvent) => {
75+
setError('');
76+
setCode(e.currentTarget.value);
77+
}}
4378
/>
4479
<a onClick={toggleRole} className="text-primary">
4580
Just kidding, I'm actually{' '}
@@ -54,6 +89,7 @@ export default () => {
5489
>
5590
Find Event
5691
</Button>
92+
{error && <Alert variant="danger">{error}</Alert>}
5793
</Form>
5894
) : (
5995
<div className="role-selector">
@@ -100,6 +136,9 @@ export default () => {
100136
a:hover {
101137
text-decoration: underline;
102138
}
139+
.join-form :global(.alert-danger) {
140+
margin-top: 10px;
141+
}
103142
`}</style>
104143
</div>
105144
);

client/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export interface Event {
1313
name: string;
1414
city: string;
1515
state: string;
16-
attendeePassword: string;
17-
mentorPassword: string;
16+
attendeePassword?: string;
17+
mentorPassword?: string;
1818
}
1919

2020
export type Role = 'attendee' | 'mentor';

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"dotenv": "^7.0.0",
3535
"express": "^4.16.4",
3636
"express-async-handler": "^1.1.4",
37+
"express-response-errors": "^1.0.4",
3738
"express-session": "^1.16.2",
3839
"fork-ts-checker-webpack-plugin": "^1.3.7",
3940
"hijackresponse": "^4.0.0",

pages/create.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ export default () => {
5050
throw new Error(json.message);
5151
}
5252

53-
console.log(json);
54-
5553
event = json;
5654
} catch (e) {
5755
setLoading(false);
@@ -62,7 +60,6 @@ export default () => {
6260
}
6361

6462
setLoading(false);
65-
console.log(event);
6663
};
6764

6865
const clearErrors = (keys: Array<keyof typeof defaultErrors>) => {
@@ -135,6 +132,9 @@ export default () => {
135132
max-width: 400px;
136133
margin: 50px auto;
137134
}
135+
.create-event-page :global(.alert-danger) {
136+
margin-top: 10px;
137+
}
138138
`}</style>
139139
</div>
140140
);

server/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import UsersRouter from 'server/routers/users';
1212
import EventsRouter from 'server/routers/events';
1313
import initDB from './lib/db';
1414
import checkCollectionExistence from './lib/checkCollectionExistence';
15+
import { responseErrorHandler } from 'express-response-errors/lib/middleware';
1516

1617
const MongoStore = require('connect-mongo')(session);
1718
dotenv.config();
@@ -69,6 +70,7 @@ nextjs.nextApp.prepare().then(async () => {
6970
app.use(PagesRouter);
7071
app.use(UsersRouter);
7172
app.use(EventsRouter);
73+
app.use(responseErrorHandler);
7274

7375
app.get('*', (req, res) => {
7476
nextjs.handle(req, res);

server/middleware/auth.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as express from 'express';
2+
import { UnauthorizedError } from 'express-response-errors';
23

34
export const requiresAuth = ({ error }: { error?: boolean } = {}) => (
45
req: express.Request,
@@ -7,7 +8,7 @@ export const requiresAuth = ({ error }: { error?: boolean } = {}) => (
78
) => {
89
if (!req.user) {
910
if (error) {
10-
return res.status(401).send({ message: 'Unauthorized, please log in' });
11+
throw new UnauthorizedError('Unauthorized, please log in');
1112
}
1213

1314
return res.redirect('/login');

server/models/schemas/User.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ const UserSchema: Schema = new Schema(
88
password: String,
99
events: [
1010
{
11-
type: Schema.Types.ObjectId,
12-
ref: 'Event',
11+
eventId: {
12+
type: Schema.Types.ObjectId,
13+
ref: 'Event',
14+
},
15+
role: {
16+
type: String,
17+
enum: ['attendee', 'mentor', 'owner'],
18+
},
1319
},
1420
],
1521
},

0 commit comments

Comments
 (0)