mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-21 11:20:17 -04:00
move files out of newui folder
This commit is contained in:
parent
6ca547cc98
commit
179047d672
38
src/App.css
38
src/App.css
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
});
|
40
src/App.tsx
40
src/App.tsx
|
@ -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
33
src/components/App.tsx
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { Redirect } from 'react-router';
|
||||
|
||||
export default function Logout() {
|
||||
localStorage.removeItem('session_token');
|
||||
|
||||
return <Redirect to="/"></Redirect>;
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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) {
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue
Block a user