move files out of newui folder

This commit is contained in:
Michael Fatemi 2021-07-02 23:16:56 -04:00
parent 6ca547cc98
commit 179047d672
58 changed files with 127 additions and 2121 deletions

View File

@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,8 +0,0 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -1,40 +0,0 @@
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import './App.css';
import AuthenticationWrapper from './components/Authentication/AuthenticationWrapper';
import Authenticator from './components/Authentication/Authenticator';
import CreateGroup from './components/CreateGroup';
import Group from './components/Group';
import Groups from './components/Groups';
import Home from './components/Home';
import Logout from './components/Logout';
import Main from './components/Main';
import MyGroups from './components/MyGroups';
import Nav from './components/Nav';
import PoolPage from './components/PoolPage';
import Profile from './components/Profile';
import UpdatePool from './components/UpdatePool';
function App() {
return (
<AuthenticationWrapper>
<BrowserRouter>
<Nav />
<Switch>
<Route component={Main} path="/about" />
<Route component={Authenticator} path="/auth/:provider/callback" />
<Route component={CreateGroup} path="/create_group" />
<Route component={MyGroups} path="/mygroups" />
<Route component={UpdatePool} path="/update_pool" />
<Route component={Group} path="/groups/:id" />
<Route component={PoolPage} path="/pools/:id" />
<Route component={Groups} path="/groups" />
<Route component={Profile} path="/profile" />
<Route component={Logout} path="/logout" />
<Route component={Home} path="/" />
</Switch>
</BrowserRouter>
</AuthenticationWrapper>
);
}
export default App;

33
src/components/App.tsx Normal file
View File

@ -0,0 +1,33 @@
import WheelShare from './WheelShare';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { lazy, Suspense } from 'react';
const Authenticator = lazy(() => import('./Authentication/Authenticator'));
const Group = lazy(() => import('./Group'));
const dev = true;
const ION_AUTHORIZATION_ENDPOINT = dev
? 'https://ion.tjhsst.edu/oauth/authorize?response_type=code&client_id=rNa6n9YSg8ftINdyVPpUsaMuxNbHLo9dh1OsOktR&scope=read&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fion%2Fcallback'
: '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() {
return (
<>
<a href={ION_AUTHORIZATION_ENDPOINT}>Login Link for Testing Oauth</a>
<div style={{ padding: '1rem' }}>
<BrowserRouter>
<Switch>
<Route path="/" exact component={WheelShare} />
<Suspense fallback={null}>
<Route path="/groups/:id" component={Group} />
<Route
component={Authenticator}
path="/auth/:provider/callback"
/>
</Suspense>
</Switch>
</BrowserRouter>
</div>
</>
);
}

View File

@ -1,6 +1,5 @@
import { useContext, useEffect, useState } from 'react';
import { Redirect, useLocation, useParams } from 'react-router-dom';
import { makeAPIPostCall } from '../../api/utils';
import AuthenticationContext from './AuthenticationContext';
export default function Authenticator() {
@ -12,10 +11,17 @@ export default function Authenticator() {
useState<'pending' | 'errored' | 'authenticated'>('pending');
useEffect(() => {
makeAPIPostCall('/create_session', { code, provider })
.then((response) => {
if (response.data.status === 'success') {
localStorage.setItem('session_token', response.data.token);
fetch('http://localhost:5000/create_session', {
method: 'post',
body: JSON.stringify({ code }),
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((data) => {
if (data.status === 'success') {
localStorage.setItem('session_token', data.token);
refreshAuthState && refreshAuthState();
setStatus('authenticated');
} else {

View File

@ -1,13 +0,0 @@
import Card from '@material-ui/core/Card';
import Typography from '@material-ui/core/Typography';
export default function Comment({ comment }: { comment: Carpool.Comment }) {
return (
<Card style={{ display: 'flex', flexDirection: 'column', padding: '1rem' }}>
<Typography variant="subtitle2">
<b>Comment by {comment.author_id}</b>
</Typography>
<Typography variant="body2">{comment.body}</Typography>
</Card>
);
}

View File

@ -1,86 +0,0 @@
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import { useState } from 'react';
import { makeAPIPostCall } from '../api/utils';
import { useHistory } from 'react-router-dom';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 140,
},
button: {
margin: theme.spacing(1),
},
}));
const CreateGroup = () => {
const history = useHistory();
const [title, setTitle] = useState('No Title');
const classes = useStyles();
const onClick = () => {
makeAPIPostCall('/groups/', {
name: title,
}).then((res) => {
handleCallback(res.data);
});
};
const handleCallback = (res: any) => {
if (res.status === 'error') {
alert('There was a problem with your form!');
} else {
history.push('/profile');
}
};
return (
<div className="container">
<Card
className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem', background: '#F3F5F4' }}
>
<CardContent>
<Typography gutterBottom variant="h5" component="h2"></Typography>
<Typography variant="body2" color="textSecondary" component="p">
<form>
<div className="form-group">
<h1 className="form-title" style={{ fontFamily: 'Impact' }}>
Create Group
</h1>
<label className="" htmlFor="title">
Group Title:{' '}
</label>
<input
type="text"
id="title"
name="title"
className="form-control d-flex"
placeholder="Enter title here..."
onChange={(event) => setTitle(event.target.value)}
/>
</div>
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={onClick}
startIcon={<CloudUploadIcon />}
>
Submit
</Button>
</form>
</Typography>
</CardContent>
</Card>
</div>
);
};
export default CreateGroup;

View File

@ -1,261 +0,0 @@
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import { useEffect, useState } from 'react';
import { makeAPIPostCall, makeAPIGetCall } from '../api/utils';
import { useHistory } from 'react-router-dom';
import PlacesAutocomplete from 'react-places-autocomplete';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 140,
},
button: {
margin: theme.spacing(1),
},
}));
const CreatePool = ({ groupID }: { groupID?: string }) => {
const history = useHistory();
const [title, setTitle] = useState('No Title');
const [capacity, setCapacity] = useState(0);
const [start, setStart] = useState('');
const [end, setEnd] = useState('');
const [direction, setDirection] = useState('pickup');
const [type, setType] = useState('offer');
const [description, setDescription] = useState('');
const classes = useStyles();
const [group, setGroup] = useState('');
const [groups, setGroups] = useState<Carpool.Group[]>([]);
const [address, setAddress] = useState('');
const handleChange = (address: string) => {
setAddress(address);
};
const handleSelect = (address: string) => {
setAddress(address);
// geocodeByAddress(address)
// .then((results) => getLatLng(results[0]))
// .then((latLng) => console.log('Success', latLng))
// .catch((error) => console.error('Error', error));
};
const onClick = () => {
console.log(address);
makeAPIPostCall('/pools/', {
title,
description,
start_time: start,
end_time: end,
capacity,
direction,
type,
group_id: group,
address,
}).then((res) => {
handleCallback(res.data);
});
};
const handleCallback = (res: any) => {
if (res.status === 'error') {
alert('There was a problem with your form!');
} else {
history.push('/profile');
}
};
useEffect(() => {
makeAPIGetCall('/users/@me/groups').then((res) => {
if (res.data.data) setGroups(res.data.data);
});
}, []);
return (
<div className="container">
<Card
className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem', background: '#F3F5F4' }}
>
<CardContent>
<div className="form-group">
<h1 className="form-title">Create Pool</h1>
<label className="" htmlFor="title">
Pool Title:{' '}
</label>
<input
type="text"
id="title"
name="title"
className="form-control d-flex"
placeholder="Enter title here..."
onChange={(event) => setTitle(event.target.value)}
></input>
</div>
<div className="form-group">
<label className="" htmlFor="capacity">
Pool Capacity:
</label>
<input
type="number"
id="capacity"
name="capacity"
className="form-control d-flex"
placeholder="0"
onChange={(event) => setCapacity(parseInt(event.target.value))}
></input>
</div>
<div className="form-group">
<label className="" htmlFor="pool_start">
Start Time:
</label>
<input
type="datetime-local"
id="pool_start"
name="pool_start"
className="form-control"
placeholder=""
onChange={(event) => setStart(event.target.value)}
></input>
</div>
<div className="form-group">
<label className="" htmlFor="pool_end">
End Time:
</label>
<input
type="datetime-local"
id="pool_end"
name="pool_end"
className="form-control"
placeholder="Enter text here..."
onChange={(event) => setEnd(event.target.value)}
></input>
</div>
<div className="form-group">
<label className="" htmlFor="pool_direction">
Direction:
</label>
<select
id="direction"
name="direction"
onChange={(event) => setDirection(event.target.value)}
>
<option value="pickup">Picking Up</option>
<option value="dropoff">Dropping Off</option>
</select>
</div>
<div className="form-group">
<label className="" htmlFor="pool_type">
Type:
</label>
<select
id="type"
name="type"
onChange={(event) => setType(event.target.value)}
>
<option value="offer">Offering carpool</option>
<option value="request">Requesting carpool</option>
</select>
</div>
<div className="form-group">
<label className="" htmlFor="title">
Pool Description:
</label>
<textarea
onChange={(event) => setDescription(event.target.value)}
id="Pool-text"
name="Pool-text"
style={{ height: '200px' }}
className="form-control"
placeholder="Enter text here..."
/>
</div>
<div className="form-group">
<label className="" htmlFor="group-select">
Group:
</label>
<select
name="group-select"
id="group-select"
onChange={(event) => setGroup(event.target.value)}
defaultValue={groupID}
>
<option value="">Select a group</option>
{groups.map((group) => (
<option key={group._id} value={group._id}>
{group.name}
</option>
))}
</select>
</div>
<div className="form-group">
<PlacesAutocomplete
value={address}
onChange={handleChange}
onSelect={handleSelect}
>
{({
getInputProps,
suggestions,
getSuggestionItemProps,
loading,
}) => (
<div>
<label className="" htmlFor="address">
Address:
</label>
<input
name="address"
id="address"
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input form-control',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map((suggestion) => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
</div>
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={onClick}
startIcon={<CloudUploadIcon />}
>
Submit
</Button>
</CardContent>
</Card>
</div>
);
};
export default CreatePool;

View File

@ -1,101 +1,75 @@
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { makeAPIGetCall } from '../api/utils';
import CreatePool from './CreatePool';
import useToggle from './NewUI/useToggle';
import Pool from './Pool';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import { Link } from 'react-router-dom';
import { IEvent } from './Event';
import EventCreatorLink from './EventCreatorLink';
import EventStream from './EventStream';
import GroupSettingsLink from './GroupSettingsLink';
import UILink from './UILink';
// eslint-disable-next-line
const SAMPLE_POOLS: Carpool.Pool[] = [
{
_id: '1234',
title: 'TJ Carpool',
description: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participant_ids: [],
comments: [
{
author_id: 'joshua_hsueh',
body: 'What is the covid vaccination status of all the participants?',
id: 'comment_0',
},
],
driver_id: 'michael',
create_time: '0',
update_time: '0',
group_id: 'test_group',
status: 'pending',
direction: 'dropoff',
author_id: 'michael',
type: 'offer',
},
];
export type IGroup = {
id: number;
events: IEvent[];
name: string;
};
export default function Group() {
// eslint-disable-next-line
const { id } = useParams<{ id: string }>();
const [error, setError] = useState(false);
const [group, setGroup] = useState<Carpool.Group>();
const [pools, setPools] = useState<Carpool.Pool[]>([]);
const [createPoolVisible, toggleCreatePoolVisible] = useToggle(false);
const fetchPools = useCallback(() => {
makeAPIGetCall(`/groups/${id}/pools`).then((res) => {
setPools(res.data.data);
});
}, [id]);
useEffect(() => fetchPools(), [fetchPools]);
const [loading, setLoading] = useState(true);
const [group, setGroup] = useState<IGroup | null>(null);
const [events, setEvents] = useState<IEvent[]>([]);
useEffect(() => {
makeAPIGetCall(`/groups/${id}`).then((res) => {
if ('error' in res.data) {
setError(true);
} else {
setGroup(res.data.data);
}
});
setLoading(true);
fetch('http://localhost:5000/api/groups/' + id)
.then((response) => response.json())
.then(setGroup)
.finally(() => setLoading(false));
fetch('http://localhost:5000/api/groups/' + id + '/events')
.then((response) => response.json())
.then(setEvents);
}, [id]);
if (error) {
return <h1 style={{ textAlign: 'center' }}>Group Not Found</h1>;
if (!group && !loading) {
return (
<div style={{ textAlign: 'center' }}>
<h1>Group Not Found</h1>
<Link to="/">Home</Link>
</div>
);
}
if (!group) {
return <h1 style={{ textAlign: 'center' }}>Loading</h1>;
return null;
}
const { name } = group;
return (
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
padding: '1rem',
textAlign: 'center',
maxWidth: '30rem',
marginLeft: 'auto',
marginRight: 'auto',
}}
>
<Typography variant="h1" align="center">
{group.name}
</Typography>
<Typography variant="h3" align="center">
Pools
</Typography>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<div>
<Button onClick={toggleCreatePoolVisible} variant="contained">
{createPoolVisible ? 'Cancel' : 'Create Pool'}
</Button>
{createPoolVisible && <CreatePool groupID={group._id} />}
</div>
{pools.map((pool, index) => (
<Pool pool={pool} triggerUpdate={fetchPools} key={index} />
))}
</div>
<h1>{name}</h1>
<UILink href="/">Home</UILink>
<br />
<br />
<GroupSettingsLink group={group} />
<br />
<EventCreatorLink group={group} />
<br />
{events && events.length > 0 ? (
<EventStream events={events} />
) : (
<span>
There are no events yet. Click 'create event' above to add one!
</span>
)}
</div>
);
}

View File

@ -1,138 +1,34 @@
import Button from '@material-ui/core/Button';
import React, { useState, useEffect } from 'react';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import Box from '@material-ui/core/Box';
import { makeAPIGetCall, makeAPIPostCall } from '../api/utils';
import { useHistory } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { IGroup } from './Group';
import GroupCreatorLink from './GroupCreatorLink';
import GroupJoinerLink from './GroupJoinerLink';
import GroupList from './GroupList';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
justifyContent: 'center',
},
media: {
height: 140,
},
button: {
margin: theme.spacing(1),
background: '#40E0D0',
'&:hover': {
background: '#FFFFFF',
},
},
}));
const Groups = () => {
const history = useHistory();
const classes = useStyles();
const [groups, setGroups] = useState<Carpool.Group[]>([
{
_id: '1234',
name: 'TJ',
creator_id: 'michael',
member_ids: [],
},
]);
export default function Groups() {
const [groups, setGroups] = useState<IGroup[]>([]);
useEffect(() => {
makeAPIGetCall('/browse/groups').then((res) => {
if (res.data.data) {
setGroups(res.data.data);
}
});
fetch('http://localhost:5000/api/groups')
.then((res) => res.json())
.then(setGroups);
}, []);
return (
<div
className=""
style={{ minHeight: '100vh', backgroundColor: '#F1EAE8' }}
>
<h1
className="d-flex justify-content-center p-4"
style={{ backgroundColor: '#F1EAE8' }}
>
Groups
</h1>
<Box textAlign="center">
<Button
variant="contained"
className={classes.button}
startIcon={<CloudUploadIcon />}
href="/create_group"
>
Create Group
</Button>
</Box>
<div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br>
{groups.map((group, index) => {
return (
<Card
className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }}
>
<CardActionArea href={'/groups/' + group._id}>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{group.name}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
></Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
size="small"
color="primary"
onClick={() => {
alert('Copied to Clipboard');
let link: string = 'localhost:3000/groups/' + group._id;
navigator.clipboard.writeText(link);
}}
>
Share
</Button>
<Button
href={'/groups/' + group._id}
size="small"
color="primary"
>
Learn More
</Button>
<button
type="submit"
onClick={() => {
makeAPIPostCall(`/groups/${group._id}/join`).then((res) => {
if (res.data.status === 'error') {
alert('There was a problem joining the group!');
} else {
history.push(`/groups/${group._id}`);
<>
<h1>Groups</h1>
<GroupJoinerLink />
<br />
<GroupCreatorLink />
<br />
{groups.length > 0 ? (
<GroupList groups={groups} />
) : (
<span>
You aren't in any groups. You can create your own by clicking 'create
group' above, or join one by asking an admin of the group to send you
an invite link.
</span>
)}
</>
);
}
});
}}
value="Request to Join"
className="btn btn-success d-flex"
>
Join Group
</button>
</CardActions>
</Card>
);
})}
</div>
</div>
);
};
export default Groups;

View File

@ -1,164 +0,0 @@
import Button from '@material-ui/core/Button';
import { useContext } from 'react';
import { ION_AUTHORIZATION_ENDPOINT } from '../api/api';
import AuthenticationContext from './Authentication/AuthenticationContext';
import ChatIcon from '@material-ui/icons/Chat';
import LockIcon from '@material-ui/icons/Lock';
import LocalTaxi from '@material-ui/icons/LocalTaxi';
import RedeemIcon from '@material-ui/icons/Redeem';
export default function Home() {
const { user, isLoggedIn } = useContext(AuthenticationContext);
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '1rem 0rem',
backgroundImage: "url('images/banner-new.jpg')",
backgroundRepeat: 'no-repeat',
color: 'white',
// backgroundSize: '',
}}
>
<h1 style={{ textShadow: '1px 1px black', fontSize: '8rem' }}>
WheelShare
</h1>
<div
style={{
display: 'flex',
flexDirection: 'row',
margin: '1rem 0rem',
fontSize: '2rem',
backgroundColor: 'rgba(1, 1, 1, 0.5)',
padding: '0.5rem 1rem',
}}
>
{!isLoggedIn ? (
<Button
onClick={() => (window.location.href = ION_AUTHORIZATION_ENDPOINT)}
>
Sign in with Ion
</Button>
) : (
'Hello ' + user?.first_name + '!'
)}
</div>
<div className="d-flex flex-column">
<section id="reinvest" style={{ paddingTop: '80px' }}>
<div className="container">
<div className="text-center">
<img
id="logo"
alt="Carpool App"
onMouseOver={(e) => (e.currentTarget.src = 'images/logo.gif')}
onMouseOut={(e) => (e.currentTarget.src = 'images/logo.png')}
className="text-center img-fluid"
src="images/logo.png"
width="500px"
height="750px"
/>
</div>
<h3 className="text-white bg-primary rounded-lg shadow-lg p-3 mb-5 mt-3">
Helping communities utilize carpooling
</h3>
</div>
</section>
<section id="about" className="p-4">
<div
className="container"
style={{ backgroundColor: 'rgba(1, 1, 1, 0.5)' }}
>
<h1 className="d-flex justify-content-center m-2 p-2">
<u>About Us</u>
</h1>
<p className="d-flex justify-content-center m-2 p-2">
Wheelshare is an app aimed to help communities find safe ways to
carpool. The app has groups where people must be approved before
joining. Upon joining, users can create their own car pool inside
that communitiy or join others.
</p>
</div>
</section>
<section id="services" className="">
<div className="bg-dark text-white p-4">
<div>
<h1 className="d-flex justify-content-center m-2 p-4">
Our Services
</h1>
<div className="row exp-grids py-3 d-inline-flex justify-content-center">
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
<div className="exp wthree">
<h5>
<LockIcon style={{ marginRight: '1em' }} />
Privacy and Security
</h5>
<div className="clearfix"></div>
<p>
All carpools are private to a community. Nobody can view a
route before being approved by an admin to the group.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
{/* <img src="images/events.jpg" alt=" " className="img-fluid" /> */}
<div className="exp wthree">
<h5>
<LocalTaxi style={{ marginRight: '1em' }} />
Optimized Routes
</h5>
<div className="clearfix" />
<p>
We provide maps for every carpool that enable riders and
drivers to choose the optimal carpools for their routes.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
{/* <img src="images/post.jpg" alt=" " className="img-fluid" /> */}
<div className="exp wthree">
<h5>
<ChatIcon style={{ marginRight: '1em' }} />
Communication
</h5>
<div className="clearfix" />
<p>
Easily communicate with others in the pool without needing
to set up an external group chat. For example, you could
coordinate based on who has been vaccinated and who
hasn't, and ensure that you are following all COVID safety
protocols.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
{/* <img
src="images/createpost.jpg"
alt=""
className="img-fluid"
/> */}
<div className="exp wthree">
<h5>
<RedeemIcon style={{ marginRight: '1em' }} />
Rewards
</h5>
<div className="clearfix" />
<p>
Every driver is given points based on how many passenger
miles they have. These points can accumulate and be shown
as badges on the driver's profile.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
);
}

View File

@ -1,7 +0,0 @@
import { Redirect } from 'react-router';
export default function Logout() {
localStorage.removeItem('session_token');
return <Redirect to="/"></Redirect>;
}

View File

@ -1,144 +0,0 @@
// import 'bootstrap/dist/css/bootstrap.min.css';
// import 'bootstrap/dist/js/bootstrap.bundle.min';
export default function Main() {
return (
<div className="d-flex flex-column">
<h1>About Us</h1>
<section
id="reinvest"
style={{
backgroundImage: "url('images/background.jpg')",
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
height: '690px',
paddingTop: '80px',
}}
>
<div className="container">
<br />
<div className="text-center">
<img
className="text-center img-fluid"
src="images/logo.png"
alt="Carpool App"
width="350px"
/>
</div>
<br />
<br />
<br />
<h3 className="text-white bg-primary rounded-lg shadow-lg p-3 mb-5">
Digitally empowering underrepresented minorities in politics
</h3>
</div>
</section>
<section id="about" className="p-4">
<div className="container">
<h1 className="d-flex justify-content-center m-2 p-2">About Us</h1>
<p className="d-flex justify-content-center m-2 p-2">
ThinkOpenly is a politics exchange platform, aiming to create a
professional and efficient connection between underrepresented
minority groups and politics. Community members can post questions
or concerns and other members can +1 the post. Professional
legislators or lawmakers can then answer or attempt to enforce laws
to support these concerns. To make this process as effective as
possible, we use NLP Machine Learning to suggest other articles or
posts to users based on previous likes. Our platform also offers
suggestions for events that coincide with their interests and free
time via Google Calendar.
</p>
</div>
</section>
<section id="services" className="">
<div className="bg-dark text-white p-4">
<div className="container">
<h1 className="d-flex justify-content-center m-2 p-4">
Our Services
</h1>
<div className="row exp-grids py-3 d-inline-flex justify-content-center">
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
<img src="images/posts.jpg" alt=" " className="img-fluid" />
<div className="exp wthree">
<h5>Browse Posts</h5>
<div className="clearfix"></div>
<p>
Easily browse through NLP generated recommended posts in
your feed. These posts match your previous interests and
recent trending political and social subjects.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
<img src="images/events.jpg" alt=" " className="img-fluid" />
<div className="exp wthree">
<h5>Browse Events</h5>
<div className="clearfix"></div>
<p>
Browse local community political events that match your
political interests in order to best advocate your concerns
and have your voice heard.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
<br />
<br />
<br />
<img src="images/post.jpg" alt=" " className="img-fluid" />
<div className="exp wthree">
<br />
<br />
<br />
<h5>Discussion Thread</h5>
<div className="clearfix"></div>
<p>
View someone's post and leave a like or comment to further
discuss the thread or show your support. Each like or
comment will make your feed give more posts or events that
are similar.
</p>
</div>
</div>
<div className="col-lg-5 col-md-7 bg-white text-dark m-2 p-4">
<br />
<br />
<br />
<img
src="images/createpost.jpg"
alt=" "
className="img-fluid"
/>
<div className="exp wthree">
<br />
<br />
<br />
<h5>Create Posts</h5>
<div className="clearfix"></div>
<p>
Create your own post anonymously for free and easily. Your
post will be seen by many others as well as politicians that
can possibly advocate and recognize your interests for your
given enough support.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="support" className="m-2">
<div className="container">
<h1 className="d-flex justify-content-center m-2 p-4">Support</h1>
<h4>Contact:</h4>
<p>@gmail.com</p>
</div>
</section>
</div>
);
}

View File

@ -1,118 +0,0 @@
import Button from '@material-ui/core/Button';
import React, { useState, useEffect } from 'react';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import Box from '@material-ui/core/Box';
import { makeAPIGetCall } from '../api/utils';
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
justifyContent: 'center',
},
media: {
height: 140,
},
button: {
margin: theme.spacing(1),
background: '#40E0D0',
'&:hover': {
background: '#FFFFFF',
},
},
}));
const MyGroups = () => {
const classes = useStyles();
const [groups, setGroups] = useState<Carpool.Group[]>();
useEffect(() => {
makeAPIGetCall('/users/@me/groups').then((res) => {
if (res.data.data) {
setGroups(res.data.data);
}
});
}, []);
return (
<div
className=""
style={{ minHeight: '100vh', backgroundColor: '#F1EAE8' }}
>
<h1
className="d-flex justify-content-center p-4"
style={{ backgroundColor: '#F1EAE8' }}
>
My Groups
</h1>
<Box textAlign="center">
<Button
variant="contained"
className={classes.button}
startIcon={<CloudUploadIcon />}
href="/create_group"
>
Create Group
</Button>
</Box>
<div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br>
{groups?.map((group, index) => {
// let background;
// if (index % 2 === 0) {
// background = '#F1EAE8';
// } else {
// background = '#FFFFFF';
// }
return (
<Card
className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }}
>
<CardActionArea href={'/groups/' + group._id}>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{group.name}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
></Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
size="small"
color="primary"
onClick={() => {
alert('Copied to Clipboard');
let link: string = 'localhost:3000/groups/' + group._id;
navigator.clipboard.writeText(link);
}}
>
Share
</Button>
<Button
href={'/groups/' + group._id}
size="small"
color="primary"
>
Learn More
</Button>
</CardActions>
</Card>
);
})}
</div>
</div>
);
};
export default MyGroups;

View File

@ -1,123 +0,0 @@
import React, { useState, useEffect } from 'react';
import { API_ENDPOINT } from '../api/api';
import { makeAPIGetCall } from '../api/utils';
const MyPools = () => {
// const id = props.match.params.id;
const [pools, setPools] = useState([
{
id: 1,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 2,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 3,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 4,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
]);
useEffect(() => {
makeAPIGetCall('/users/@me/pools').then((res) => {
if (res.data.data) {
setPools(res.data.data);
}
});
}, []);
const maybePluralize = (count: number, noun: string, suffix = 's') =>
`${count} ${noun}${count !== 1 ? suffix : ''}`;
return (
<div className="bg-dark" style={{ minHeight: '100vh' }}>
<h1
className="d-flex justify-content-center p-4"
style={{ backgroundColor: '#F1EAE8', fontFamily: 'Impact' }}
>
Pools
</h1>
<a
className="btn btn-large btn-success"
href="/create_pool"
style={{ fontFamily: 'Courier New' }}
>
Create Pool
</a>
<div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br>
{pools.map((pool, index) => {
let background;
if (index % 2 === 0) {
background = '#F1EAE8';
} else {
background = '#FFFFFF';
}
return (
<div
className="card card-body text-left"
style={{ backgroundColor: background }}
>
<a href={'/pools/' + pool.id} className="card-title">
{pool.pool_title}
</a>
<p className="text-left">
Capacity: {pool.participants.length} / {pool.capacity}
</p>
<p className="text-left">Start Time: {pool.start_time}</p>
<p className="text-left">End Time: {pool.end_time}</p>
<p className="text-warning">
{maybePluralize(pool.comments.length, 'comment')}
</p>
<a
className="btn btn-large btn-success"
href="/create_pool"
style={{ fontFamily: 'Courier New', maxWidth: '135px' }}
>
Update Pool
</a>
</div>
);
})}
</div>
</div>
);
};
export default MyPools;

View File

@ -1,104 +0,0 @@
import { AppBar, Toolbar } from '@material-ui/core';
import { IconButton } from '@material-ui/core';
import { Home } from '@material-ui/icons';
import { List, ListItem, ListItemText } from '@material-ui/core';
import { makeStyles } from '@material-ui/core';
import { Container } from '@material-ui/core';
const useStyles = makeStyles({
navbarDisplayFlex: {
display: `flex`,
justifyContent: `space-between`,
},
navDisplayFlex: {
display: `flex`,
justifyContent: `space-between`,
},
linkText: {
textDecoration: `none`,
textTransform: `uppercase`,
color: `white`,
},
'linkText:hover': {
textDecoration: `none`,
textTransform: `uppercase`,
color: `white`,
},
});
const navLinks = [
{ title: `Profile`, path: `/profile` },
{ title: `Groups`, path: `/groups` },
{ title: `My Groups`, path: `/mygroups` },
];
const Nav = () => {
const classes = useStyles();
return (
<AppBar position="static" style={{ background: '#4287f5' }}>
<Toolbar>
<Container maxWidth="xl" className={classes.navbarDisplayFlex}>
<IconButton href="/" edge="start" color="inherit" aria-label="home">
<Home fontSize="large" />
</IconButton>
<List
component="nav"
aria-labelledby="main navigation"
className={classes.navbarDisplayFlex} // this
>
{navLinks.map(({ title, path }) => (
<a href={path} key={title} className={classes.linkText}>
<ListItem button>
<ListItemText primary={title} />
</ListItem>
</a>
))}
</List>
</Container>
</Toolbar>
</AppBar>
// <AppBar className="navbar navbar-expand-lg navbar-dark bg-dark">
// <button
// className="navbar-toggler"
// type="button"
// data-toggle="collapse"
// data-target="#navbarNavDropdown"
// aria-controls="navbarNavDropdown"
// aria-expanded="false"
// aria-label="Toggle navigation"
// >
// <span className="navbar-toggler-icon"></span>
// </button>
// <div className="collapse navbar-collapse" id="navbarNavDropdown">
// <ul className="navbar-nav mr-auto">
// <li className="nav-item">
// <a className="nav-link text-white" href="/">
// Carpool <span className="sr-only">(current)</span>
// </a>
// </li>
// <li className="nav-item">
// <a className="nav-link text-white" href="/profile">
// Profile <span className="sr-only">(current)</span>
// </a>
// </li>
// <li className="nav-item">
// <a className="nav-link text-white" href="/groups">
// Groups
// </a>
// </li>
// <li className="nav-item">
// <a className="nav-link text-white" href="/mygroups">
// MyGroups
// </a>
// </li>
// <li className="nav-item">
// <a className="nav-link text-white" href="/mypools">
// MyPools
// </a>
// </li>
// </ul>
// </div>
// </AppBar>
);
};
export default Nav;

View File

@ -1,23 +0,0 @@
import WheelShare from './WheelShare';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { lazy, Suspense } from 'react';
const Group = lazy(() => import('./Group'));
export default function App() {
return (
<>
<a href="">Login Link for Testing Oauth</a>
<div style={{ padding: '1rem' }}>
<BrowserRouter>
<Switch>
<Route path="/" exact component={WheelShare} />
<Suspense fallback={null}>
<Route path="/groups/:id" component={Group} />
</Suspense>
</Switch>
</BrowserRouter>
</div>
</>
);
}

View File

@ -1,75 +0,0 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import { Link } from 'react-router-dom';
import { IEvent } from './Event';
import EventCreatorLink from './EventCreatorLink';
import EventStream from './EventStream';
import GroupSettingsLink from './GroupSettingsLink';
import UILink from './UILink';
export type IGroup = {
id: number;
events: IEvent[];
name: string;
};
export default function Group() {
const { id } = useParams<{ id: string }>();
const [loading, setLoading] = useState(true);
const [group, setGroup] = useState<IGroup | null>(null);
const [events, setEvents] = useState<IEvent[]>([]);
useEffect(() => {
setLoading(true);
fetch('http://localhost:5000/api/groups/' + id)
.then((response) => response.json())
.then(setGroup)
.finally(() => setLoading(false));
fetch('http://localhost:5000/api/groups/' + id + '/events')
.then((response) => response.json())
.then(setEvents);
}, [id]);
if (!group && !loading) {
return (
<div style={{ textAlign: 'center' }}>
<h1>Group Not Found</h1>
<Link to="/">Home</Link>
</div>
);
}
if (!group) {
return null;
}
const { name } = group;
return (
<div
style={{
textAlign: 'center',
maxWidth: '30rem',
marginLeft: 'auto',
marginRight: 'auto',
}}
>
<h1>{name}</h1>
<UILink href="/">Home</UILink>
<br />
<br />
<GroupSettingsLink group={group} />
<br />
<EventCreatorLink group={group} />
<br />
{events && events.length > 0 ? (
<EventStream events={events} />
) : (
<span>
There are no events yet. Click 'create event' above to add one!
</span>
)}
</div>
);
}

View File

@ -1,34 +0,0 @@
import { useState, useEffect } from 'react';
import { IGroup } from './Group';
import GroupCreatorLink from './GroupCreatorLink';
import GroupJoinerLink from './GroupJoinerLink';
import GroupList from './GroupList';
export default function Groups() {
const [groups, setGroups] = useState<IGroup[]>([]);
useEffect(() => {
fetch('http://localhost:5000/api/groups')
.then((res) => res.json())
.then(setGroups);
}, []);
return (
<>
<h1>Groups</h1>
<GroupJoinerLink />
<br />
<GroupCreatorLink />
<br />
{groups.length > 0 ? (
<GroupList groups={groups} />
) : (
<span>
You aren't in any groups. You can create your own by clicking 'create
group' above, or join one by asking an admin of the group to send you
an invite link.
</span>
)}
</>
);
}

View File

@ -1,232 +0,0 @@
import { useState, useCallback, useRef, useContext } from 'react';
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import Textarea from '@material-ui/core/TextareaAutosize';
import Typography from '@material-ui/core/Typography';
import Comment from './Comment';
import { makeAPIPostCall } from '../api/utils';
import AuthenticationContext from './Authentication/AuthenticationContext';
import PoolMap from './PoolMap';
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
// eslint-disable-next-line
const SAMPLE_POOL = {
id: '123',
title: 'TJ Carpool',
description: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participant_ids: [],
comments: [
{
author_id: 'myfatemi04',
id: '1234',
body: "what's the vaccination status of everyone?",
},
],
driver_id: 'None',
create_time: '1234',
update_time: '1234',
group_id: 'tj',
status: 'pending',
direction: 'dropoff',
author_id: 'michael',
type: 'offer',
};
export default function Pool({
pool,
triggerUpdate,
}: {
pool: Carpool.Pool;
triggerUpdate: Function;
}) {
console.log(pool);
const { user } = useContext(AuthenticationContext);
const [address, setAddress] = useState('');
const handleChange = (address: string) => {
setAddress(address);
};
const handleSelect = (address: string) => {
setAddress(address);
};
const commentTextareaRef = useRef<HTMLTextAreaElement>(null);
const [commentStatus, setCommentStatus] =
useState<null | 'pending' | 'errored'>(null);
const onComment = useCallback<React.MouseEventHandler<HTMLButtonElement>>(
(e) => {
e.preventDefault();
if (!commentTextareaRef.current) {
// Wait for ref to be ready
return;
}
if (commentTextareaRef.current.value.length === 0) {
// Noop, no comment to send
return;
}
setCommentStatus('pending');
makeAPIPostCall(`/pools/${pool._id}/comment`, {
body: commentTextareaRef.current!.value,
})
.then(() => {
setCommentStatus(null);
commentTextareaRef.current!.value = '';
triggerUpdate();
})
.catch(() => {
setCommentStatus('errored');
});
},
[pool._id, triggerUpdate]
);
const onRegister = useCallback(() => {
makeAPIPostCall(`/pools/${pool._id}/join`)
.then(() => geocodeByAddress(address))
.then((results) => getLatLng(results[0]))
.then(({ lat, lng }) =>
makeAPIPostCall(`/addresses`, {
pool: pool._id,
location: address,
lat: lat,
lng: lng,
})
)
.then(() => triggerUpdate());
}, [pool._id, address, triggerUpdate]);
const onUnregister = useCallback(() => {
makeAPIPostCall(`/pools/${pool._id}/leave`)
.then(() =>
makeAPIPostCall(`/addresses/remove`, {
pool: pool._id,
})
)
.then(() => triggerUpdate());
}, [pool._id, triggerUpdate]);
const mapField = (
<div className="form-group">
<PlacesAutocomplete
value={address}
onChange={handleChange}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<label className="" htmlFor="address">
Address:
</label>
<input
name="address"
id="address"
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input form-control',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map((suggestion) => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
</div>
);
return (
<Card style={{ margin: '3rem auto', padding: '1rem 1rem', width: '50%' }}>
{pool && (
<>
<Typography variant="h2" align="center">
{pool.title}
</Typography>
<Typography variant="subtitle1">
<b>Capacity</b>: {pool.participant_ids?.length} / {pool.capacity}
</Typography>
<Typography variant="subtitle1">
<b>Start Time</b>: {pool.start_time || '3:00 PM'}
</Typography>
<Typography variant="subtitle1">
<b>End Time</b>: {pool.end_time || '3:30 PM'}
</Typography>
<Typography variant="body1">{pool.description}</Typography>
{user && pool.participant_ids?.includes(user._id)
? undefined
: mapField}
{user && (
<Button
variant="contained"
color="primary"
style={{ marginTop: '0.5rem' }}
onClick={
pool.participant_ids?.includes(user._id)
? onUnregister
: onRegister
}
>
{pool.participant_ids?.includes(user._id)
? 'Unregister'
: 'Register'}
</Button>
)}
<hr />
<PoolMap pool={pool} />
<hr />
<Textarea
cols={80}
ref={commentTextareaRef}
placeholder="Post a comment..."
disabled={commentStatus === 'pending'}
style={{ margin: '0.5rem 0rem' }}
/>
<Button
variant="contained"
onClick={onComment}
style={{ margin: '0.5rem 0rem' }}
disabled={commentStatus === 'pending'}
>
Post Comment
</Button>
<Typography variant="subtitle1">
{commentStatus === 'errored' && 'Error posting comment'}
</Typography>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{pool.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
</>
)}
</Card>
);
}

View File

@ -1,51 +0,0 @@
import GoogleMapReact from 'google-map-react';
import { useCallback } from 'react';
import { makeAPIGetCall } from '../api/utils';
const position = { lat: 38.817, lng: -77.1679 };
export type AddressMarker = {
user: string;
pool: string;
location: string;
lat: string;
lng: string;
};
export default function PoolMap({ pool }: { pool: Carpool.Pool }) {
const renderMarkers = useCallback(
(map: any, maps: any) => {
let markers: any[] = [];
makeAPIGetCall(`/addresses/pool/${pool._id}`).then((res) => {
if (res.data.data) {
res.data.data.forEach((element: AddressMarker) => {
let marker = new maps.Marker({
position: {
lat: parseFloat(element.lat),
lng: parseFloat(element.lng),
},
map,
title: 'Anonymous Address',
});
markers.push(marker);
});
}
});
},
[pool._id]
);
return (
<div style={{ height: '50vh', width: '100%' }}>
<GoogleMapReact
bootstrapURLKeys={{
key: 'AIzaSyDUnWIrt-H4RuP2YFLpVPz4oAjBhpOOoyI',
}}
defaultCenter={position}
defaultZoom={11}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }: any) => renderMarkers(map, maps)}
/>
</div>
);
}

View File

@ -1,25 +0,0 @@
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { makeAPIGetCall } from '../api/utils';
import Pool from './Pool';
export default function PoolPage() {
const id = useParams<{ id: string }>().id;
const [pool, setPool] = useState<Carpool.Pool>();
const fetchData = useCallback(() => {
makeAPIGetCall(`/pools/${id}`).then((response) => {
if (response.data.data) {
setPool(response.data.data);
}
});
}, [id]);
useEffect(() => fetchData(), [fetchData]);
if (pool != null) {
return <Pool pool={pool} triggerUpdate={fetchData} />;
} else {
return null;
}
}

View File

@ -1,117 +0,0 @@
import { useState, useEffect } from 'react';
import { API_ENDPOINT } from '../api/api';
import { makeAPIGetCall } from '../api/utils';
const maybePluralize = (count: number, noun: string, suffix = 's') =>
`${count} ${noun}${count !== 1 ? suffix : ''}`;
const Pools = () => {
const [pools, setPools] = useState<Carpool.Pool[]>([
/*
{
id: 1,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 2,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 3,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},
{
id: 4,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: [
'What is the covid vaccination status of all the participants?',
],
},*/
]);
useEffect(() => {
makeAPIGetCall(`/users/@me/pools`).then((res) => {
if (res.data.data) {
setPools(res.data.data);
}
});
}, []);
return (
<div className="bg-dark" style={{ minHeight: '100vh' }}>
<h1
className="d-flex justify-content-center p-4"
style={{ backgroundColor: '#F1EAE8', fontFamily: 'Impact' }}
>
Pools
</h1>
<a
className="btn btn-large btn-success"
href="/create_pool"
style={{ fontFamily: 'Courier New' }}
>
Create Pool
</a>
<div className="container" style={{ fontFamily: 'Courier New' }}>
<br></br>
{pools.map((pool, index) => {
let background;
if (index % 2 === 0) {
background = '#F1EAE8';
} else {
background = '#FFFFFF';
}
return (
<div
className="card card-body text-left"
style={{ backgroundColor: background }}
>
<a href={'/pools/' + pool._id} className="card-title">
{pool.title}
</a>
<p className="text-left">
Capacity: {pool.participant_ids.length} / {pool.capacity}
</p>
<p className="text-left">Start Time: {pool.start_time}</p>
<p className="text-left">End Time: {pool.end_time}</p>
<p className="" style={{ color: '#9E6105' }}>
{maybePluralize(pool.comments.length, 'comment')}
</p>
</div>
);
})}
</div>
</div>
);
};
export default Pools;

View File

@ -1,123 +0,0 @@
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import { useContext, useEffect, useState } from 'react';
import { makeAPIGetCall } from '../api/utils';
import AuthenticationContext from './Authentication/AuthenticationContext';
const useStyles = makeStyles({
root: {
maxWidth: 345,
},
media: {
height: 140,
},
});
const Profile = () => {
const { user } = useContext(AuthenticationContext);
const [groups, setGroups] = useState<Carpool.Group[]>([]);
const [pools, setPools] = useState<Carpool.Pool[]>([]);
const classes = useStyles();
useEffect(() => {
makeAPIGetCall('/users/@me/pools').then((res) => {
if (res.data.data) setPools(res.data.data);
});
makeAPIGetCall('/users/@me/groups').then((res) => {
if (res.data.data) setGroups(res.data.data);
});
}, []);
if (!user) {
return <h1>Please Sign In</h1>;
}
return (
<div
className=""
style={{ minHeight: '100vh', backgroundColor: '#F1EAE8' }}
>
<h1
className="d-flex justify-content-center p-4"
style={{ backgroundColor: '#F1EAE8' }}
>
Profile
</h1>
<div className="container">
<h2>
<u>My Pools (private)</u>
</h2>
<div>
{pools.map((pool) => {
return (
<Card
className={classes.root + 'd-inline-flex'}
style={{ margin: '0.5rem' }}
>
<CardActionArea href={'/pools/' + pool._id}>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{pool.title}
</Typography>
<Typography
variant="body2"
color="textSecondary"
component="p"
>
{pool.description}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
size="small"
color="primary"
onClick={() => {
let link: string = 'localhost:3000/pools/' + pool._id;
navigator.clipboard.writeText(link);
}}
>
Share
</Button>
<Button
href={'/pools/' + pool._id}
size="small"
color="primary"
>
Learn More
</Button>
</CardActions>
</Card>
);
})}
</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>
);
};
export default Profile;

View File

@ -1,117 +0,0 @@
import { useState, useEffect, FormEventHandler } from 'react';
import { useParams } from 'react-router-dom';
import { makeAPIGetCall } from '../api/utils';
const UpdatePool = () => {
const id = useParams<{ id: string }>().id;
// eslint-disable-next-line
const [pool, setPool] = useState({
id: 1,
pool_title: 'TJ Carpool',
pool_text: 'Carpool from TJ track to homes',
start_time: '4/10/2021 3:00 PM',
end_time: '4/10/2021 4:00 PM',
capacity: 2,
participants: [],
comments: ['What is the covid vaccination status of all the participants?'],
});
const onSubmit: FormEventHandler<HTMLFormElement> = (e) => {
e.preventDefault();
makeAPIGetCall(`/pools/${id}`).then((res) => {
console.log(res);
});
};
useEffect(() => {
makeAPIGetCall(`/pools/${id}`).then((res) => {
if (res.data.data) setPool(res.data.data);
});
}, [id]);
return (
<div
className="bg-dark"
style={{ minHeight: '100vh', fontFamily: 'Courier New' }}
>
<div
className="container card card-body text-left "
style={{ backgroundColor: '#F1EAE8' }}
>
<form onSubmit={onSubmit}>
<div className="form-group">
<h1 className="form-title" style={{ fontFamily: 'Impact' }}>
Update Pool
</h1>
<label className="" htmlFor="title">
Pool Title:{' '}
</label>
<input
type="text"
id="title"
name="title"
className="form-control d-flex"
placeholder="Enter title here..."
></input>
</div>
<div className="form-group">
<label className="" htmlFor="capacity">
Pool Capacity:
</label>
<input
type="number"
id="capacity"
name="capacity"
className="form-control d-flex"
placeholder="5"
></input>
</div>
<div className="form-group">
<label className="" htmlFor="pool_start">
Start Time:
</label>
<input
type="datetime-local"
id="pool_start"
name="pool_start"
className="form-control"
placeholder=""
></input>
</div>
<div className="form-group">
<label className="" htmlFor="pool_end">
End Time:
</label>
<input
type="datetime-local"
id="pool_end"
name="pool_end"
className="form-control"
placeholder="Enter text here..."
></input>
</div>
<div className="form-group">
<label className="" htmlFor="title">
Pool Description:
</label>
<textarea
id="Pool-text"
name="Pool-text"
style={{ height: '200px' }}
className="form-control"
placeholder="Enter text here..."
></textarea>
</div>
<input
className="btn btn-success text-left"
type="submit"
value="Update"
/>
<br />
</form>
</div>
</div>
);
};
export default UpdatePool;

View File

@ -1,5 +1,5 @@
import { useState, useEffect, useCallback } from 'react';
import { getPlaceDetails, PlaceDetails } from '../../api/google';
import { getPlaceDetails, PlaceDetails } from '../api/google';
import useThrottle from './useThrottle';
export default function usePlace(placeId: string | null) {

View File

@ -1,7 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/NewUI/App';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(