Skip to content

Commit 7e7f435

Browse files
committed
event creation
1 parent 6918e6e commit 7e7f435

22 files changed

+498
-43
lines changed

client/Header.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ const anonRoutes = {
1313
};
1414

1515
const authedRoutes = {
16-
left: [{ href: '/event', label: 'Event' }],
16+
left: [
17+
{ href: '/event', label: 'Event' },
18+
{ href: '/create', label: 'Create' },
19+
],
1720
right: [
1821
{ href: '/account', label: 'Account' },
1922
{ href: '/logout', label: 'Log out' },

client/components/account/DeleteAccountModal.tsx renamed to client/account/DeleteAccountModal.tsx

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

66
interface Props {
77
isShowing: boolean;
@@ -15,9 +15,7 @@ function DeleteAccountModal({ isShowing, hideModal }: Props) {
1515
setLoading(true);
1616

1717
try {
18-
await fetch('/api/delete_account', {
19-
method: 'POST',
20-
});
18+
await post('/api/delete_account');
2119
} catch (e) {
2220
setLoading(false);
2321
throw e; //TODO messaging

client/components/LogoutLink.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import * as React from 'react';
2-
import fetch from 'isomorphic-fetch';
2+
import { post } from 'client/lib/requests';
33

44
export default ({ children }: { children: React.ReactNode }) => {
55
const logout = async () => {
6-
await fetch('/logout', {
7-
method: 'POST',
8-
});
6+
await post('/logout');
97

108
window.location.href = '/';
119
};

client/eventPage/JoinForm.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import * as React from 'react';
2+
import { Form, Button } from 'react-bootstrap';
3+
import { Role, InputEvent } from 'client/types';
4+
import { get } from 'client/lib/requests';
5+
6+
export default () => {
7+
const [role, setRole] = React.useState<Role | ''>('');
8+
const [code, setCode] = React.useState('');
9+
const [loading, setLoading] = React.useState(false);
10+
11+
const capitalizedRole = role.slice(0, 1).toUpperCase() + role.slice(1);
12+
13+
const toggleRole = () => {
14+
if (role === 'attendee') {
15+
setRole('mentor');
16+
} else if (role === 'mentor') {
17+
setRole('attendee');
18+
}
19+
};
20+
21+
const findEvent = async (e: React.FormEvent) => {
22+
e.preventDefault();
23+
setLoading(true);
24+
const res = await get(`/api/events/find?code=${code}`);
25+
console.log(res);
26+
setLoading(false);
27+
};
28+
29+
return (
30+
<div className="join-form">
31+
{role ? (
32+
<Form>
33+
<Form.Group>
34+
<Form.Label>
35+
Enter the {capitalizedRole} Code for your Event
36+
</Form.Label>
37+
<Form.Control
38+
value={code}
39+
required
40+
type="text"
41+
placeholder={`Enter ${capitalizedRole} Code`}
42+
onChange={(e: InputEvent) => setCode(e.currentTarget.value)}
43+
/>
44+
<a onClick={toggleRole} className="text-primary">
45+
Just kidding, I'm actually{' '}
46+
{role === 'mentor' ? 'an attendee' : 'a mentor'}.
47+
</a>
48+
</Form.Group>
49+
<Button
50+
type="submit"
51+
variant="primary"
52+
disabled={loading}
53+
onClick={findEvent}
54+
>
55+
Find Event
56+
</Button>
57+
</Form>
58+
) : (
59+
<div className="role-selector">
60+
<h1>I am...</h1>
61+
<div>
62+
<Button
63+
variant="secondary"
64+
size="lg"
65+
onClick={() => setRole('mentor')}
66+
>
67+
A Mentor
68+
</Button>
69+
<Button
70+
variant="primary"
71+
size="lg"
72+
onClick={() => setRole('attendee')}
73+
>
74+
An Attendee
75+
</Button>
76+
</div>
77+
</div>
78+
)}
79+
<style jsx>{`
80+
.join-form :global(form) {
81+
max-width: 400px;
82+
margin: 0 auto;
83+
}
84+
.role-selector {
85+
text-align: center;
86+
max-width: 400px;
87+
margin: 30px auto;
88+
}
89+
.role-selector > div {
90+
margin-top: 50px;
91+
display: flex;
92+
justify-content: space-around;
93+
}
94+
a {
95+
cursor: pointer;
96+
display: inline-block;
97+
margin-top: 20px;
98+
font-size: 14px;
99+
}
100+
a:hover {
101+
text-decoration: underline;
102+
}
103+
`}</style>
104+
</div>
105+
);
106+
};

client/lib/requests.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import fetch from 'isomorphic-fetch';
2+
3+
export const get = fetch;
4+
5+
export const post = (uri: string, body?: Object) =>
6+
fetch(uri, {
7+
method: 'POST',
8+
headers: {
9+
Accept: 'application/json',
10+
'Content-Type': 'application/json',
11+
},
12+
body: body ? JSON.stringify(body) : undefined,
13+
});

client/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1+
import * as React from 'react';
2+
13
export interface User {
24
name: string;
35
}
46

57
export interface AppStore {
68
user: User | null;
79
}
10+
11+
export interface Event {
12+
_id: string;
13+
name: string;
14+
city: string;
15+
state: string;
16+
attendeePassword: string;
17+
mentorPassword: string;
18+
}
19+
20+
export type Role = 'attendee' | 'mentor';
21+
22+
export type InputEvent = React.ChangeEvent<HTMLInputElement>;

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"author": "",
2121
"license": "ISC",
2222
"dependencies": {
23+
"@types/lodash": "^4.14.139",
2324
"@types/react-dom": "^16.9.1",
2425
"@zeit/next-typescript": "^1.1.1",
2526
"axios": "^0.19.0",
@@ -37,6 +38,7 @@
3738
"fork-ts-checker-webpack-plugin": "^1.3.7",
3839
"hijackresponse": "^4.0.0",
3940
"isomorphic-fetch": "^2.2.1",
41+
"lodash": "^4.17.15",
4042
"module-alias": "^2.2.0",
4143
"mongodb": "^3.3.2",
4244
"mongoose": "^5.7.1",
@@ -45,6 +47,7 @@
4547
"nodemon": "^1.18.11",
4648
"passport": "^0.4.0",
4749
"passport-local": "^1.0.0",
50+
"random-words": "^1.1.0",
4851
"react": "^16.8.6",
4952
"react-bootstrap": "^1.0.0-beta.12",
5053
"react-dom": "^16.9.0",

pages/account.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { Button } from 'react-bootstrap';
3-
import DeleteAccountModal from 'client/components/account/DeleteAccountModal';
3+
import DeleteAccountModal from 'client/account/DeleteAccountModal';
44

55
export default () => {
66
const [showDeleteModal, setShowDeleteModal] = React.useState(false);

pages/create.tsx

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import * as React from 'react';
2+
import { Form, Button, Alert } from 'react-bootstrap';
3+
import { InputEvent } from 'client/types';
4+
import { post } from 'client/lib/requests';
5+
6+
const defaultErrors = {
7+
name: '',
8+
endDate: '',
9+
general: '',
10+
};
11+
12+
export default () => {
13+
const [name, setName] = React.useState('');
14+
const [city, setCity] = React.useState('');
15+
const [state, setState] = React.useState('');
16+
const [endDate, setEndDate] = React.useState('');
17+
const [loading, setLoading] = React.useState(false);
18+
const [errors, setErrors] = React.useState(defaultErrors);
19+
20+
const onCreate = async () => {
21+
clearErrors(['name', 'endDate', 'general']);
22+
if (!name || !name.trim().length) {
23+
return setErrors({
24+
...errors,
25+
name: 'Name must not be empty',
26+
});
27+
}
28+
29+
if (!endDate) {
30+
return setErrors({
31+
...errors,
32+
endDate: 'You must provide an end date',
33+
});
34+
}
35+
36+
setLoading(true);
37+
38+
let event;
39+
40+
try {
41+
const res = await post('/api/events/create', {
42+
name,
43+
city,
44+
state,
45+
endDate,
46+
});
47+
const json = await res.json();
48+
49+
if (!res.ok) {
50+
throw new Error(json.message);
51+
}
52+
53+
console.log(json);
54+
55+
event = json;
56+
} catch (e) {
57+
setLoading(false);
58+
return setErrors({
59+
...errors,
60+
general: e.message,
61+
});
62+
}
63+
64+
setLoading(false);
65+
console.log(event);
66+
};
67+
68+
const clearErrors = (keys: Array<keyof typeof defaultErrors>) => {
69+
const updatedErrors = { ...errors };
70+
keys.forEach(key => (updatedErrors[key] = ''));
71+
setErrors(updatedErrors);
72+
};
73+
74+
return (
75+
<div className="create-event-page">
76+
<Form>
77+
<Form.Group>
78+
<Form.Label>Event Name</Form.Label>
79+
<Form.Control
80+
value={name}
81+
type="text"
82+
placeholder={`Name of the event`}
83+
onChange={(e: InputEvent) => {
84+
clearErrors(['name']);
85+
setName(e.currentTarget.value);
86+
}}
87+
/>
88+
{errors.name && <Alert variant="danger">{errors.name}</Alert>}
89+
</Form.Group>
90+
<Form.Group>
91+
<Form.Label>City</Form.Label>
92+
<Form.Control
93+
value={city}
94+
type="text"
95+
placeholder={`City where the event is being held`}
96+
onChange={(e: InputEvent) => setCity(e.currentTarget.value)}
97+
/>
98+
</Form.Group>
99+
<Form.Group>
100+
<Form.Label>State</Form.Label>
101+
<Form.Control
102+
value={state}
103+
type="text"
104+
placeholder={`State/Province where the event is being held`}
105+
onChange={(e: InputEvent) => setState(e.currentTarget.value)}
106+
/>
107+
</Form.Group>
108+
<Form.Group>
109+
<Form.Label>When does this event end?</Form.Label>
110+
<Form.Control
111+
value={endDate}
112+
type="datetime-local"
113+
onChange={(e: InputEvent) => {
114+
clearErrors(['endDate']);
115+
setEndDate(e.currentTarget.value);
116+
}}
117+
/>
118+
{errors.endDate && <Alert variant="danger">{errors.endDate}</Alert>}
119+
</Form.Group>
120+
<Button
121+
type="submit"
122+
disabled={loading}
123+
onClick={(e: React.FormEvent) => {
124+
e.preventDefault();
125+
onCreate();
126+
}}
127+
variant="primary"
128+
>
129+
Create
130+
</Button>
131+
{errors.general && <Alert variant="danger">{errors.general}</Alert>}
132+
</Form>
133+
<style jsx>{`
134+
.create-event-page {
135+
max-width: 400px;
136+
margin: 50px auto;
137+
}
138+
`}</style>
139+
</div>
140+
);
141+
};

pages/event.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as React from 'react';
2+
import JoinForm from 'client/eventPage/JoinForm';
3+
4+
export default () => {
5+
return (
6+
<div className="event-page">
7+
<JoinForm />
8+
<style jsx>{`
9+
.event-page {
10+
margin: 50px auto;
11+
}
12+
`}</style>
13+
</div>
14+
);
15+
};

0 commit comments

Comments
 (0)