updated design for groups

This commit is contained in:
Joshua Hsueh 2021-04-10 23:26:45 -04:00
commit 7fc9f17f44
18 changed files with 9056 additions and 9372 deletions

View File

@ -5,6 +5,7 @@
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.3", "@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@react-google-maps/api": "^2.1.1",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",

View File

@ -16,6 +16,7 @@ import Main from './components/Main';
import './App.css'; import './App.css';
import Authenticator from './components/Authenticator'; import Authenticator from './components/Authenticator';
import AuthenticationWrapper from './components/AuthenticationWrapper'; import AuthenticationWrapper from './components/AuthenticationWrapper';
import Logout from './components/Logout';
function App() { function App() {
return ( return (
@ -27,12 +28,13 @@ function App() {
<Route component={Authenticator} path="/auth/:provider/callback" /> <Route component={Authenticator} path="/auth/:provider/callback" />
<Route component={CreatePool} path="/create_pool" /> <Route component={CreatePool} path="/create_pool" />
<Route component={CreateGroup} path="/create_group" /> <Route component={CreateGroup} path="/create_group" />
<Route component={Groups} path="/groups" />
<Route component={MyGroups} path="/mygroups" /> <Route component={MyGroups} path="/mygroups" />
<Route component={UpdatePool} path="/update_pool" /> <Route component={UpdatePool} path="/update_pool" />
<Route component={Group} path="/group/:id" /> <Route component={Group} path="/groups/:id" />
<Route component={Pool} path="/pool/:id" /> <Route component={Pool} path="/pools/:id" />
<Route component={Groups} path="/groups" />
<Route component={Profile} path="/profile" /> <Route component={Profile} path="/profile" />
<Route component={Logout} path="/logout" />
<Route component={Home} path="/" /> <Route component={Home} path="/" />
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>

View File

@ -32,11 +32,11 @@ export async function createSession(
} }
export async function getMe(): Promise<Carpool.User> { export async function getMe(): Promise<Carpool.User> {
let result = await makeAPIGetCall('/user', { userID: '@me' }); let result = await makeAPIGetCall('/users/@me');
return result.data.data; return result.data.data;
} }
export async function getPublicUser(id: string): Promise<Carpool.PublicUser> { export async function getPublicUser(id: string): Promise<Carpool.PublicUser> {
let result = await makeAPIGetCall('/user', { userID: id }); let result = await makeAPIGetCall(`/users/${id}`);
return result.data.data; return result.data.data;
} }

16
src/api/google.ts Normal file
View File

@ -0,0 +1,16 @@
export const GOOGLE_MAPS_API_KEY = 'AIzaSyDUnWIrt-H4RuP2YFLpVPz4oAjBhpOOoyI';
export async function searchForPlaces(query: string) {
const url = new URL(
'https://maps.googleapis.com/maps/api/place/findplacefromtext/json'
);
url.searchParams.set('key', GOOGLE_MAPS_API_KEY);
url.searchParams.set('input', query);
url.searchParams.set('inputtype', 'textquery');
url.searchParams.set('fields', 'place_id,name,formatted_address');
let res = await fetch(url.toString(), { mode: 'no-cors' });
let json = await res.json();
return json;
}

View File

@ -1,6 +1,6 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { Redirect, useLocation, useParams } from 'react-router-dom'; import { Redirect, useLocation, useParams } from 'react-router-dom';
import { API_ENDPOINT } from '../api/api'; import { makeAPIPostCall } from '../api/utils';
import AuthenticationContext from './AuthenticationContext'; import AuthenticationContext from './AuthenticationContext';
export default function Authenticator() { export default function Authenticator() {
@ -13,26 +13,15 @@ export default function Authenticator() {
); );
useEffect(() => { useEffect(() => {
fetch(`${API_ENDPOINT}/create_session`, { makeAPIPostCall('/create_session', { code, provider })
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
code,
provider,
}),
})
.then((response) => { .then((response) => {
response.json().then((json) => { if (response.data.status === 'success') {
if (json.status === 'success') { localStorage.setItem('session_token', response.data.token);
localStorage.setItem('session_token', json.token); refreshAuthState && refreshAuthState();
refreshAuthState && refreshAuthState(); setStatus('authenticated');
setStatus('authenticated'); } else {
} else { setStatus('errored');
setStatus('errored'); }
}
});
}) })
.catch(() => { .catch(() => {
setStatus('errored'); setStatus('errored');

View File

@ -1,12 +1,11 @@
import { useCallback } from 'react'; import Button from '@material-ui/core/Button';
import { makeAPIPostCall } from '../api/utils';
import Card from '@material-ui/core/Card'; import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent'; import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import { useState, useEffect } from 'react';
import CloudUploadIcon from '@material-ui/icons/CloudUpload'; import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import { useState } from 'react';
import { makeAPIPostCall } from '../api/utils';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@ -22,14 +21,9 @@ const useStyles = makeStyles((theme) => ({
const CreateGroup = () => { const CreateGroup = () => {
const [title, setTitle] = useState('No Title'); const [title, setTitle] = useState('No Title');
const classes = useStyles(); const classes = useStyles();
useEffect(() => {}, []);
const onClick = () => { const onClick = () => {
console.log({ makeAPIPostCall('/groups/', { title });
title: title,
});
makeAPIPostCall('/group', {
title,
});
}; };
return ( return (

View File

@ -1,11 +1,12 @@
import { makeAPIPostCall } from '../api/utils'; import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card'; import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent'; import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload'; import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import { useState, useEffect } from 'react'; import { useEffect, useState } from 'react';
import { searchForPlaces } from '../api/google';
import { makeAPIPostCall } from '../api/utils';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
maxWidth: 345, maxWidth: 345,
@ -30,7 +31,7 @@ const CreatePool = () => {
const [group, setGroup] = useState(''); const [group, setGroup] = useState('');
const onClick = () => { const onClick = () => {
makeAPIPostCall('/pool', { makeAPIPostCall('/pools/', {
title, title,
description, description,
start_time: start, start_time: start,
@ -49,128 +50,140 @@ const CreatePool = () => {
style={{ margin: '0.5rem', background: '#F3F5F4' }} style={{ margin: '0.5rem', background: '#F3F5F4' }}
> >
<CardContent> <CardContent>
<Typography gutterBottom variant="h5" component="h2"></Typography> <div className="form-group">
<Typography variant="body2" color="textSecondary" component="p"> <h1 className="form-title">Create Pool</h1>
<form> <label className="" htmlFor="title">
<div className="form-group"> Pool Title:{' '}
<h1 className="form-title" style={{ fontFamily: 'Impact' }}> </label>
Create Pool <input
</h1> type="text"
<label className="" htmlFor="title"> id="title"
Pool Title:{' '} name="title"
</label> className="form-control d-flex"
<input placeholder="Enter title here..."
type="text" onChange={(event) => setTitle(event.target.value)}
id="title" ></input>
name="title" </div>
className="form-control d-flex" <div className="form-group">
placeholder="Enter title here..." <label className="" htmlFor="capacity">
onChange={(event) => setTitle(event.target.value)} Pool Capacity:
></input> </label>
</div> <input
<div className="form-group"> type="number"
<label className="" htmlFor="capacity"> id="capacity"
Pool Capacity: name="capacity"
</label> className="form-control d-flex"
<input placeholder="0"
type="number" onChange={(event) => setCapacity(parseInt(event.target.value))}
id="capacity" ></input>
name="capacity" </div>
className="form-control d-flex" <div className="form-group">
placeholder="0" <label className="" htmlFor="pool_start">
onChange={(event) => Start Time:
setCapacity(parseInt(event.target.value)) </label>
} <input
></input> type="datetime-local"
</div> id="pool_start"
<div className="form-group"> name="pool_start"
<label className="" htmlFor="pool_start"> className="form-control"
Start Time: placeholder=""
</label> onChange={(event) => setStart(event.target.value)}
<input ></input>
type="datetime-local" </div>
id="pool_start" <div className="form-group">
name="pool_start" <label className="" htmlFor="pool_end">
className="form-control" End Time:
placeholder="" </label>
onChange={(event) => setStart(event.target.value)} <input
></input> type="datetime-local"
</div> id="pool_end"
<div className="form-group"> name="pool_end"
<label className="" htmlFor="pool_end"> className="form-control"
End Time: placeholder="Enter text here..."
</label> onChange={(event) => setEnd(event.target.value)}
<input ></input>
type="datetime-local" </div>
id="pool_end" <div className="form-group">
name="pool_end" <label className="" htmlFor="pool_direction">
className="form-control" Direction:
placeholder="Enter text here..." </label>
onChange={(event) => setEnd(event.target.value)} <select
></input> id="direction"
</div> name="direction"
<div className="form-group"> onChange={(event) => setDirection(event.target.value)}
<label className="" htmlFor="pool_direction"> >
Direction: <option value="pickup">Picking Up</option>
</label> <option value="dropoff">Dropping Off</option>
<select </select>
id="direction" </div>
name="direction" <div className="form-group">
onChange={(event) => setDirection(event.target.value)} <label className="" htmlFor="pool_type">
> Type:
<option value="pickup">Picking Up</option> </label>
<option value="dropoff">Dropping Off</option> <select
</select> id="type"
</div> name="type"
<div className="form-group"> onChange={(event) => setType(event.target.value)}
<label className="" htmlFor="pool_type"> >
Type: <option value="offer">Offering carpool</option>
</label> <option value="request">Requesting carpool</option>
<select </select>
id="type" </div>
name="type" <div className="form-group">
onChange={(event) => setType(event.target.value)} <label className="" htmlFor="title">
> Pool Description:
<option value="offer">Offering carpool</option> </label>
<option value="request">Requesting carpooll</option> <textarea
</select> onChange={(event) => setDescription(event.target.value)}
</div> id="Pool-text"
<div className="form-group"> name="Pool-text"
<label className="" htmlFor="title"> style={{ height: '200px' }}
Pool Description: className="form-control"
</label> placeholder="Enter text here..."
<textarea />
onChange={(event) => setDescription(event.target.value)} </div>
id="Pool-text" <div className="form-group">
name="Pool-text" <label className="" htmlFor="pool_start">
style={{ height: '200px' }} Group:
className="form-control" </label>
placeholder="Enter text here..." <input
/> type="text"
</div> className="form-control"
<div className="form-group"> placeholder=""
<label className="" htmlFor="pool_start"> onChange={(event) => setGroup(event.target.value)}
Group: ></input>
</label> </div>
<input <div className="form-group">
type="text" <label className="" htmlFor="location">
className="form-control" Location:
placeholder="" </label>
onChange={(event) => setGroup(event.target.value)} <input
></input> type="text"
</div> className="form-control"
<Button id="location_input"
variant="contained" ></input>
color="primary" <button
className={classes.button} onClick={(e) => {
onClick={onClick} e.preventDefault();
startIcon={<CloudUploadIcon />} let input = document.getElementById(
> 'location_input'
Submit ) as HTMLInputElement;
</Button> let places = searchForPlaces(input.value);
<br /> console.log(places);
</form> }}
</Typography> >
Search
</button>
</div>
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={onClick}
startIcon={<CloudUploadIcon />}
>
Submit
</Button>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>

View File

@ -10,7 +10,7 @@ const maybePluralize = (count: number, noun: string, suffix = 's') =>
const SAMPLE_POOLS: Carpool.Pool[] = [ const SAMPLE_POOLS: Carpool.Pool[] = [
{ {
id: '1234', _id: '1234',
title: 'TJ Carpool', title: 'TJ Carpool',
description: 'Carpool from TJ track to homes', description: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM', start_time: '4/10/2021 3:00 PM',
@ -43,7 +43,7 @@ export default function Group() {
const [pools, setPools] = useState<Carpool.Pool[]>(SAMPLE_POOLS); const [pools, setPools] = useState<Carpool.Pool[]>(SAMPLE_POOLS);
useEffect(() => { useEffect(() => {
makeAPIGetCall('/group', { groupID: id }).then((res) => { makeAPIGetCall(`/groups/${id}`).then((res) => {
if ('error' in res.data) { if ('error' in res.data) {
setError(true); setError(true);
} else { } else {
@ -51,7 +51,7 @@ export default function Group() {
} }
}); });
makeAPIGetCall('/group_pools', { groupID: id }).then((res) => { makeAPIGetCall(`/groups/${id}/pools`).then((res) => {
setPools(res.data.data); setPools(res.data.data);
}); });
}, [id]); }, [id]);
@ -90,7 +90,7 @@ export default function Group() {
{pools.map((pool, index) => { {pools.map((pool, index) => {
return ( return (
<Card style={{ margin: '0.5em' }} key={index}> <Card style={{ margin: '0.5em' }} key={index}>
<a href={'/Pool/' + pool.id} className="card-title"> <a href={'/pools/' + pool._id} className="card-title">
{pool.title} {pool.title}
</a> </a>
<p className="text-left"> <p className="text-left">

View File

@ -8,6 +8,7 @@ import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload'; import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
import { makeAPIGetCall } from '../api/utils';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@ -45,10 +46,23 @@ const Groups = () => {
} }
}); });
}; };
const [groups, setGroups] = useState<Carpool.Group[]>([
{
_id: '1234',
name: 'TJ',
creator_id: 'michael',
member_ids: [],
},
]);
useEffect(() => { useEffect(() => {
callAPI(); makeAPIGetCall('/browse/groups').then((res) => {
if (res.data.data) {
setGroups(res.data.data);
}
});
}, []); }, []);
return ( return (
<div <div
className="" className=""
@ -72,22 +86,17 @@ const Groups = () => {
</Box> </Box>
<div className="container" style={{ fontFamily: 'Courier New' }}> <div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br> <br></br>
{state.MyGroups.map((group, index) => {
let background; {groups.map((group, index) => {
if (index % 2 === 0) {
background = '#F1EAE8';
} else {
background = '#FFFFFF';
}
return ( return (
<Card <Card
className={classes.root + 'd-inline-flex'} className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }} style={{ margin: '0.5rem' }}
> >
<CardActionArea href={'/group/' + group.id}> <CardActionArea href={'/group/' + group._id}>
<CardContent> <CardContent>
<Typography gutterBottom variant="h5" component="h2"> <Typography gutterBottom variant="h5" component="h2">
{group.group_title} {group.name}
</Typography> </Typography>
<Typography <Typography
variant="body2" variant="body2"
@ -102,19 +111,27 @@ const Groups = () => {
size="small" size="small"
color="primary" color="primary"
onClick={() => { onClick={() => {
let link: string = 'localhost:3000/group/' + group.id; alert('Copied to Clipboard');
let link: string = 'localhost:3000/group/' + group._id;
navigator.clipboard.writeText(link); navigator.clipboard.writeText(link);
}} }}
> >
Share Share
</Button> </Button>
<Button <Button
href={'/group/' + group.id} href={'/group/' + group._id}
size="small" size="small"
color="primary" color="primary"
> >
Learn More Learn More
</Button> </Button>
<form action={'/requestgroup/' + group._id} method="POST">
<input
type="submit"
value="Request to Join"
className="btn btn-success d-flex"
/>
</form>
</CardActions> </CardActions>
</Card> </Card>
); );

View File

@ -8,6 +8,7 @@ import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload'; import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
import { makeAPIGetCall } from '../api/utils';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@ -45,10 +46,23 @@ const MyGroups = () => {
} }
}); });
}; };
const [groups, setGroups] = useState<Carpool.Group[]>([
{
_id: '1234',
name: 'TJ',
creator_id: '12345Q',
member_ids: [],
},
]);
useEffect(() => { useEffect(() => {
callAPI(); makeAPIGetCall('/browse/groups').then((res) => {
if (res.data.data) {
setGroups(res.data.data);
}
});
}, []); }, []);
return ( return (
<div <div
className="" className=""
@ -72,7 +86,7 @@ const MyGroups = () => {
</Box> </Box>
<div className="container" style={{ fontFamily: 'Courier New' }}> <div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br> <br></br>
{state.MyGroups.map((group, index) => { {groups.map((group, index) => {
let background; let background;
if (index % 2 === 0) { if (index % 2 === 0) {
background = '#F1EAE8'; background = '#F1EAE8';
@ -84,10 +98,10 @@ const MyGroups = () => {
className={classes.root + 'd-inline-flex'} className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }} style={{ margin: '0.5rem' }}
> >
<CardActionArea href={'/group/' + group.id}> <CardActionArea href={'/group/' + group._id}>
<CardContent> <CardContent>
<Typography gutterBottom variant="h5" component="h2"> <Typography gutterBottom variant="h5" component="h2">
{group.group_title} {group.name}
</Typography> </Typography>
<Typography <Typography
variant="body2" variant="body2"
@ -102,14 +116,15 @@ const MyGroups = () => {
size="small" size="small"
color="primary" color="primary"
onClick={() => { onClick={() => {
let link: string = 'localhost:3000/group/' + group.id; alert('Copied to Clipboard');
let link: string = 'localhost:3000/group/' + group._id;
navigator.clipboard.writeText(link); navigator.clipboard.writeText(link);
}} }}
> >
Share Share
</Button> </Button>
<Button <Button
href={'/group/' + group.id} href={'/group/' + group._id}
size="small" size="small"
color="primary" color="primary"
> >

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { API_ENDPOINT } from '../api/api'; import { API_ENDPOINT } from '../api/api';
import { makeAPIGetCall } from '../api/utils';
const MyPools = () => { const MyPools = () => {
// const id = props.match.params.id; // const id = props.match.params.id;
@ -55,14 +56,11 @@ const MyPools = () => {
]); ]);
useEffect(() => { useEffect(() => {
console.log(process.env); makeAPIGetCall('/users/@me/pools').then((res) => {
fetch(`${API_ENDPOINT}/my_pools`) if (res.data.data) {
.then((response) => response.json()) setPools(res.data.data);
.then((json) => { }
if (json) { });
setPools(json.data);
}
});
}, []); }, []);
const maybePluralize = (count: number, noun: string, suffix = 's') => const maybePluralize = (count: number, noun: string, suffix = 's') =>
@ -96,7 +94,7 @@ const MyPools = () => {
className="card card-body text-left" className="card card-body text-left"
style={{ backgroundColor: background }} style={{ backgroundColor: background }}
> >
<a href={'/Pool/' + pool.id} className="card-title"> <a href={'/pools/' + pool.id} className="card-title">
{pool.pool_title} {pool.pool_title}
</a> </a>
<p className="text-left"> <p className="text-left">

View File

@ -5,7 +5,7 @@ import Card from '@material-ui/core/Card';
import Textarea from '@material-ui/core/TextareaAutosize'; import Textarea from '@material-ui/core/TextareaAutosize';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Comment from './Comment'; import Comment from './Comment';
import { makeAPIPostCall } from '../api/utils'; import { makeAPIGetCall, makeAPIPostCall } from '../api/utils';
import AuthenticationContext from './AuthenticationContext'; import AuthenticationContext from './AuthenticationContext';
// eslint-disable-next-line // eslint-disable-next-line
@ -76,8 +76,8 @@ export default function Pool() {
const onRegister = useCallback(() => { const onRegister = useCallback(() => {
if (user) { if (user) {
let userID = user.id; let userID = user._id;
makeAPIPostCall('/join_pool', { id }).then(() => { makeAPIPostCall(`/pools/${id}/join`).then(() => {
if (pool) { if (pool) {
setPool({ setPool({
...pool, ...pool,
@ -89,13 +89,11 @@ export default function Pool() {
}, [user, id, pool]); }, [user, id, pool]);
useEffect(() => { useEffect(() => {
fetch(`${process.env.REACT_APP_API_ENDPOINT}/pool/${id}`) makeAPIGetCall(`/pools/${id}`).then((response) => {
.then((response) => response.json()) if (response.data.data) {
.then((data) => { setPool(response.data.data);
if (data !== undefined) { }
setPool(data); });
}
});
}, [id]); }, [id]);
return ( return (
@ -106,7 +104,7 @@ export default function Pool() {
{pool.title} {pool.title}
</Typography> </Typography>
<Typography variant="subtitle1"> <Typography variant="subtitle1">
<b>Capacity</b>: {pool.participant_ids.length} / {pool.capacity} <b>Capacity</b>: {pool.participant_ids?.length} / {pool.capacity}
</Typography> </Typography>
<Typography variant="subtitle1"> <Typography variant="subtitle1">
<b>Start Time</b>: {pool.start_time} <b>Start Time</b>: {pool.start_time}
@ -122,7 +120,7 @@ export default function Pool() {
style={{ marginTop: '0.5rem' }} style={{ marginTop: '0.5rem' }}
onClick={onRegister} onClick={onRegister}
> >
{pool.participant_ids.includes(user.id) {pool.participant_ids?.includes(user._id)
? 'Unregister' ? 'Unregister'
: 'Register'} : 'Register'}
</Button> </Button>

View File

@ -0,0 +1,3 @@
export default function PoolMap() {
//
}

View File

@ -1,5 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { API_ENDPOINT } from '../api/api'; import { API_ENDPOINT } from '../api/api';
import { makeAPIGetCall } from '../api/utils';
const maybePluralize = (count: number, noun: string, suffix = 's') => const maybePluralize = (count: number, noun: string, suffix = 's') =>
`${count} ${noun}${count !== 1 ? suffix : ''}`; `${count} ${noun}${count !== 1 ? suffix : ''}`;
@ -58,14 +59,11 @@ const Pools = () => {
]); ]);
useEffect(() => { useEffect(() => {
console.log(process.env); makeAPIGetCall(`/users/@me/pools`).then((res) => {
fetch(`${API_ENDPOINT}/my_pools`) if (res.data.data) {
.then((response) => response.json()) setPools(res.data.data);
.then((json) => { }
if (json) { });
setPools(json.data);
}
});
}, []); }, []);
return ( return (
@ -97,7 +95,7 @@ const Pools = () => {
className="card card-body text-left" className="card card-body text-left"
style={{ backgroundColor: background }} style={{ backgroundColor: background }}
> >
<a href={'/Pool/' + pool.id} className="card-title"> <a href={'/pools/' + pool._id} className="card-title">
{pool.title} {pool.title}
</a> </a>
<p className="text-left"> <p className="text-left">
@ -105,7 +103,7 @@ const Pools = () => {
</p> </p>
<p className="text-left">Start Time: {pool.start_time}</p> <p className="text-left">Start Time: {pool.start_time}</p>
<p className="text-left">End Time: {pool.end_time}</p> <p className="text-left">End Time: {pool.end_time}</p>
<p className="" style={{color: '#9E6105'}}> <p className="" style={{ color: '#9E6105' }}>
{maybePluralize(pool.comments.length, 'comment')} {maybePluralize(pool.comments.length, 'comment')}
</p> </p>
</div> </div>

View File

@ -20,14 +20,18 @@ const useStyles = makeStyles({
const Profile = () => { const Profile = () => {
const { user } = useContext(AuthenticationContext); const { user } = useContext(AuthenticationContext);
// const [groups, setGroups] = useState<Carpool.Group[]>([]); const [groups, setGroups] = useState<Carpool.Group[]>([]);
const [pools, setPools] = useState<Carpool.Pool[]>([]); const [pools, setPools] = useState<Carpool.Pool[]>([]);
const classes = useStyles(); const classes = useStyles();
useEffect(() => { useEffect(() => {
makeAPIGetCall('/my_pools').then((res) => { makeAPIGetCall('/users/@me/pools').then((res) => {
if (res.data.data) setPools(res.data.data); if (res.data.data) setPools(res.data.data);
}); });
makeAPIGetCall('/users/@me/groups').then((res) => {
if (res.data.data) setGroups(res.data.data);
});
}, []); }, []);
if (!user) { if (!user) {
@ -47,16 +51,16 @@ const Profile = () => {
</h1> </h1>
<div className="container"> <div className="container">
<h2> <h2>
<u>{user.username}'s Pools</u> <u>My Pools (private)</u>
</h2> </h2>
<div className=""> <div>
{pools.map((pool) => { {pools.map((pool) => {
return ( return (
<Card <Card
className={classes.root + 'd-inline-flex'} className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }} style={{ margin: '0.5rem' }}
> >
<CardActionArea href={'/pool/' + pool.id}> <CardActionArea href={'/pools/' + pool._id}>
<CardContent> <CardContent>
<Typography gutterBottom variant="h5" component="h2"> <Typography gutterBottom variant="h5" component="h2">
{pool.title} {pool.title}
@ -75,14 +79,14 @@ const Profile = () => {
size="small" size="small"
color="primary" color="primary"
onClick={() => { onClick={() => {
let link: string = 'localhost:3000/pool/' + pool.id; let link: string = 'localhost:3000/pools/' + pool._id;
navigator.clipboard.writeText(link); navigator.clipboard.writeText(link);
}} }}
> >
Share Share
</Button> </Button>
<Button <Button
href={'/pool/' + pool.id} href={'/pools/' + pool._id}
size="small" size="small"
color="primary" color="primary"
> >
@ -93,6 +97,24 @@ const Profile = () => {
); );
})} })}
</div> </div>
<h2>
<u>My Groups (private)</u>
<div>
{groups.map((group) => {
return (
<Card
key={group._id}
style={{ padding: '0.5rem', margin: '0.5rem' }}
>
<h1>
<a href={'/groups/' + group._id}>{group.name}</a>
</h1>
</Card>
);
})}
</div>
</h2>
</div> </div>
</div> </div>
); );

View File

@ -1,10 +1,6 @@
import React, { import { useState, useEffect, FormEventHandler } from 'react';
useState,
useEffect,
useCallback,
FormEventHandler,
} from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { makeAPIGetCall } from '../api/utils';
const UpdatePool = () => { const UpdatePool = () => {
const id = useParams<{ id: string }>().id; const id = useParams<{ id: string }>().id;
@ -21,26 +17,17 @@ const UpdatePool = () => {
comments: ['What is the covid vaccination status of all the participants?'], comments: ['What is the covid vaccination status of all the participants?'],
}); });
const callAPI = useCallback(() => {
fetch(`${process.env.REACT_APP_API_ENDPOINT}/pool/${id}`)
.then((response) => response.json())
.then((data) => {
if (data !== undefined) {
setPool(data);
}
});
}, [id]);
const onSubmit: FormEventHandler<HTMLFormElement> = (e) => { const onSubmit: FormEventHandler<HTMLFormElement> = (e) => {
e.preventDefault(); e.preventDefault();
fetch(`${process.env.REACT_APP_API_ENDPOINT}/update_pool`) makeAPIGetCall(`/pools/${id}`).then((res) => {
.then((response) => response.json()) console.log(res);
.then((data) => { });
console.log(data);
});
}; };
useEffect(() => { useEffect(() => {
callAPI(); makeAPIGetCall(`/pools/${id}`).then((res) => {
}, [callAPI]); if (res.data.data) setPool(res.data.data);
});
}, [id]);
return ( return (
<div <div
className="bg-dark" className="bg-dark"

8
src/types.d.ts vendored
View File

@ -1,6 +1,6 @@
declare namespace Carpool { declare namespace Carpool {
export interface Group { export interface Group {
id: string; _id: string;
name: string; name: string;
member_ids: string[]; member_ids: string[];
creator_id: string; creator_id: string;
@ -8,14 +8,14 @@ declare namespace Carpool {
// Omits the email attribute // Omits the email attribute
export interface PublicUser { export interface PublicUser {
id: string; _id: string;
username: string; username: string;
first_name: string; first_name: string;
last_name: string; last_name: string;
} }
export interface User { export interface User {
id: string; _id: string;
email: string; email: string;
username: string; username: string;
first_name: string; first_name: string;
@ -31,7 +31,7 @@ declare namespace Carpool {
export type Status = 'pending' | 'cancelled' | 'completed' | 'interrupted'; export type Status = 'pending' | 'cancelled' | 'completed' | 'interrupted';
export interface Pool { export interface Pool {
id: string; _id: string;
title: string; title: string;
description: string; description: string;
participant_ids: string[]; participant_ids: string[];

17877
yarn.lock

File diff suppressed because it is too large Load Diff