diff --git a/src/components/App.tsx b/src/components/App.tsx
index fca7101..686ef68 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -1,6 +1,9 @@
-import WheelShare from './WheelShare';
+import { lazy, Suspense, useContext } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
-import { lazy, Suspense } from 'react';
+import AuthenticationContext from './Authentication/AuthenticationContext';
+import logout from './Authentication/logout';
+import UIButton from './UIButton';
+import WheelShare from './WheelShare';
const Authenticator = lazy(() => import('./Authentication/Authenticator'));
const Group = lazy(() => import('./Group'));
@@ -11,23 +14,37 @@ const ION_AUTHORIZATION_ENDPOINT = dev
: 'https://ion.tjhsst.edu/oauth/authorize?response_type=code&client_id=rNa6n9YSg8ftINdyVPpUsaMuxNbHLo9dh1OsOktR&scope=read&redirect_uri=https%3A%2F%2Fwheelshare.space%2Fauth%2Fion%2Fcallback';
export default function App() {
+ const { isLoggedIn, user } = useContext(AuthenticationContext);
return (
- <>
- Login Link for Testing Oauth
-
-
-
-
-
-
-
-
-
-
-
- >
+
+ {isLoggedIn ? (
+
+ {user!.name}{' '}
+
+ Log out
+
+
+ ) : (
+
Log in
+ )}
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/Authentication/AuthenticationContext.ts b/src/components/Authentication/AuthenticationContext.ts
index 5c267e9..4e0f362 100644
--- a/src/components/Authentication/AuthenticationContext.ts
+++ b/src/components/Authentication/AuthenticationContext.ts
@@ -1,8 +1,14 @@
import { createContext } from 'react';
+export type User = {
+ name: string;
+ id: number;
+ email?: string;
+};
+
export type AuthState = {
isLoggedIn: boolean | null;
- user: Carpool.User | null;
+ user: User | null;
/**
* Function that can be used to trigger an auth state refresh.
diff --git a/src/components/Authentication/AuthenticationWrapper.tsx b/src/components/Authentication/AuthenticationWrapper.tsx
index e0c7716..d438d1f 100644
--- a/src/components/Authentication/AuthenticationWrapper.tsx
+++ b/src/components/Authentication/AuthenticationWrapper.tsx
@@ -16,16 +16,21 @@ export default function AuthenticationWrapper({
});
const refreshAuthState = useCallback(() => {
- if (sessionToken) {
- getMe().then((user) => {
- if (user) {
- setAuthState({ isLoggedIn: true, user, refreshAuthState });
- } else {
- setAuthState({ isLoggedIn: false, user: null, refreshAuthState });
- }
- });
- } else {
+ const loggedOut = () =>
setAuthState({ isLoggedIn: false, user: null, refreshAuthState });
+
+ if (sessionToken) {
+ getMe()
+ .then((user) => {
+ if (user) {
+ setAuthState({ isLoggedIn: true, user, refreshAuthState });
+ } else {
+ loggedOut();
+ }
+ })
+ .catch(loggedOut);
+ } else {
+ loggedOut();
}
}, [sessionToken]);
diff --git a/src/components/Authentication/Authenticator.tsx b/src/components/Authentication/Authenticator.tsx
index 96e7ddf..83f9313 100644
--- a/src/components/Authentication/Authenticator.tsx
+++ b/src/components/Authentication/Authenticator.tsx
@@ -10,22 +10,31 @@ export default function Authenticator() {
const { refreshAuthState } = useContext(AuthenticationContext);
const [status, setStatus] =
useState<'pending' | 'errored' | 'authenticated'>('pending');
+ const [token, setToken] = useState(null);
useEffect(() => {
createSession(code!)
.then((data) => {
if (data.status === 'success') {
+ console.log('Success! Token:', data.token);
+ setToken(data.token);
localStorage.setItem('session_token', data.token);
- refreshAuthState && refreshAuthState();
setStatus('authenticated');
} else {
+ console.log('Authentication failure.');
+ setToken(null);
+ localStorage.removeItem('session_token');
setStatus('errored');
}
})
.catch(() => {
setStatus('errored');
});
- }, [code, provider, refreshAuthState]);
+ }, [code, provider]);
+
+ useEffect(() => {
+ refreshAuthState && refreshAuthState();
+ }, [token, refreshAuthState]);
switch (status) {
case 'authenticated':
diff --git a/src/components/Authentication/logout.ts b/src/components/Authentication/logout.ts
new file mode 100644
index 0000000..9538883
--- /dev/null
+++ b/src/components/Authentication/logout.ts
@@ -0,0 +1,4 @@
+export default function logout() {
+ localStorage.removeItem('session_token');
+ window.location.href = '/';
+}
diff --git a/src/components/Event.tsx b/src/components/Event.tsx
index b02014a..e3ecc69 100644
--- a/src/components/Event.tsx
+++ b/src/components/Event.tsx
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react';
-import { post, removeEventSignup } from './api';
+import { addEventSignup, removeEventSignup } from './api';
import { green, lightgrey } from './colors';
import latlongdist, { R_miles } from './latlongdist';
import UIButton from './UIButton';
@@ -313,15 +313,14 @@ export default function Event({ event }: { event: IEvent }) {
if (
interested === true &&
- (prev.placeId !== placeId || prev.eventId !== event.id)
+ (prev.placeId !== placeId || prev.eventId !== event.id) &&
+ placeId !== null
) {
prev.placeId = placeId;
prev.eventId = event.id;
prev.interested = true;
- post(`/events/${event.id}/signup`, {
- placeId,
- }).finally(() => setUpdating(false));
+ addEventSignup(event.id, placeId!).finally(() => setUpdating(false));
return;
}
}, [event.id, interested, placeId, updating]);
diff --git a/src/components/EventCreator.tsx b/src/components/EventCreator.tsx
index 2b1a2f0..547f5ca 100644
--- a/src/components/EventCreator.tsx
+++ b/src/components/EventCreator.tsx
@@ -1,5 +1,5 @@
import { Dispatch, SetStateAction, useCallback, useState } from 'react';
-import { post } from './api';
+import { createEvent } from './api';
import { toggleBit } from './bits';
import { green, lightgrey } from './colors';
import { IGroup } from './Group';
@@ -120,7 +120,7 @@ export default function EventCreator({ group }: { group: IGroup }) {
!durationIsNegative &&
!creating;
- const createEvent = useCallback(() => {
+ const onClickedCreateEvent = useCallback(() => {
if (!creating) {
if (startTime === null) {
console.warn(
@@ -129,12 +129,19 @@ export default function EventCreator({ group }: { group: IGroup }) {
return;
}
+ if (placeId === null) {
+ console.warn(
+ 'Tried tro create an event where the placeId was unspecified.'
+ );
+ return;
+ }
+
const duration =
endTime !== null ? (endTime.getTime() - startTime.getTime()) / 60 : 0;
setCreating(true);
- post('/events', {
+ createEvent({
name,
startTime,
duration,
@@ -143,7 +150,6 @@ export default function EventCreator({ group }: { group: IGroup }) {
placeId,
daysOfWeek,
})
- .then((response) => response.json())
.then(({ id }) => {
setCreatedEventId(id);
})
@@ -211,7 +217,7 @@ export default function EventCreator({ group }: { group: IGroup }) {
)}
{createdEventId === -1 ? (
{creating ? 'Creating event' : 'Create event'}
diff --git a/src/components/GroupCreator.tsx b/src/components/GroupCreator.tsx
index f967386..660935f 100644
--- a/src/components/GroupCreator.tsx
+++ b/src/components/GroupCreator.tsx
@@ -1,5 +1,5 @@
import { useCallback, useState } from 'react';
-import { post } from './api';
+import { createGroup } from './api';
import UIButton from './UIButton';
import UILink from './UILink';
import UISecondaryBox from './UISecondaryBox';
@@ -11,13 +11,10 @@ export default function GroupCreator() {
useState(null);
const [createdGroupId, setCreatedGroupId] = useState(0);
const [creating, setCreating] = useState(false);
- const createGroup = useCallback(() => {
+ const onClickedCreateGroup = useCallback(() => {
if (!creating) {
setCreating(true);
- post('/groups', {
- name,
- })
- .then((res) => res.json())
+ createGroup(name)
.then(({ id }) => {
setCreationSuccessful(true);
setCreatedGroupId(id);
@@ -36,7 +33,7 @@ export default function GroupCreator() {
Name
{creating ? 'Creating group' : 'Create group'}
diff --git a/src/components/api.ts b/src/components/api.ts
index a9d04a0..b704b12 100644
--- a/src/components/api.ts
+++ b/src/components/api.ts
@@ -1,26 +1,32 @@
-export async function post(path: string, data: any) {
+async function post(path: string, data: any) {
const res = await fetch('http://localhost:5000/api' + path, {
method: 'post',
body: JSON.stringify(data),
headers: {
+ Authorization: 'Bearer ' + localStorage.getItem('session_token'),
'Content-Type': 'application/json',
},
});
return await res.json();
}
-export async function delete$(path: string) {
+async function delete$(path: string) {
const res = await fetch('http://localhost:5000/api' + path, {
method: 'delete',
headers: {
+ Authorization: 'Bearer ' + localStorage.getItem('session_token'),
'Content-Type': 'application/json',
},
});
return await res.json();
}
-export async function get(path: string) {
- const res = await fetch('http://localhost:5000/api' + path);
+async function get(path: string) {
+ const res = await fetch('http://localhost:5000/api' + path, {
+ headers: {
+ Authorization: 'Bearer ' + localStorage.getItem('session_token'),
+ },
+ });
return await res.json();
}
@@ -41,10 +47,47 @@ export async function getPlaceDetails(
return await get('/place/' + placeId);
}
+export async function addEventSignup(eventId: number, placeId: string) {
+ post(`/events/${eventId}/signup`, {
+ placeId,
+ });
+}
+
export async function removeEventSignup(eventId: number) {
return await delete$(`/events/${eventId}/signup`);
}
+export async function createEvent({
+ name,
+ startTime,
+ duration,
+ endDate,
+ groupId,
+ placeId,
+ daysOfWeek,
+}: {
+ name: string;
+ startTime: Date;
+ duration: number;
+ endDate: Date | null;
+ groupId: number;
+ placeId: string;
+ daysOfWeek: number;
+}) {
+ const { id } = await post('/events', {
+ name,
+ startTime,
+ duration,
+ endDate,
+ groupId,
+ placeId,
+ daysOfWeek,
+ });
+ return {
+ id,
+ };
+}
+
export async function getEvents() {
return await get('/events');
}
@@ -65,6 +108,15 @@ export async function deleteGroup(id: number) {
return await delete$('/groups/' + id);
}
+export async function createGroup(name: string) {
+ const result = await post('/groups', {
+ name,
+ });
+ return {
+ id: result.id,
+ };
+}
+
export async function getMe() {
return await get('/users/@me');
}
diff --git a/src/index.js b/src/index.js
index a307dc0..8b15e68 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,10 +3,13 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
+import AuthenticationWrapper from './components/Authentication/AuthenticationWrapper';
ReactDOM.render(
-
+
+
+
,
document.getElementById('root')
);