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 { useContext, useEffect, useState } from 'react';
|
||||||
import { Redirect, useLocation, useParams } from 'react-router-dom';
|
import { Redirect, useLocation, useParams } from 'react-router-dom';
|
||||||
import { makeAPIPostCall } from '../../api/utils';
|
|
||||||
import AuthenticationContext from './AuthenticationContext';
|
import AuthenticationContext from './AuthenticationContext';
|
||||||
|
|
||||||
export default function Authenticator() {
|
export default function Authenticator() {
|
||||||
|
@ -12,10 +11,17 @@ export default function Authenticator() {
|
||||||
useState<'pending' | 'errored' | 'authenticated'>('pending');
|
useState<'pending' | 'errored' | 'authenticated'>('pending');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
makeAPIPostCall('/create_session', { code, provider })
|
fetch('http://localhost:5000/create_session', {
|
||||||
.then((response) => {
|
method: 'post',
|
||||||
if (response.data.status === 'success') {
|
body: JSON.stringify({ code }),
|
||||||
localStorage.setItem('session_token', response.data.token);
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
localStorage.setItem('session_token', data.token);
|
||||||
refreshAuthState && refreshAuthState();
|
refreshAuthState && refreshAuthState();
|
||||||
setStatus('authenticated');
|
setStatus('authenticated');
|
||||||
} else {
|
} 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 { useEffect, useState } from 'react';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import { useParams } from 'react-router';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { Link } from 'react-router-dom';
|
||||||
import { useParams } from 'react-router-dom';
|
import { IEvent } from './Event';
|
||||||
import { makeAPIGetCall } from '../api/utils';
|
import EventCreatorLink from './EventCreatorLink';
|
||||||
import CreatePool from './CreatePool';
|
import EventStream from './EventStream';
|
||||||
import useToggle from './NewUI/useToggle';
|
import GroupSettingsLink from './GroupSettingsLink';
|
||||||
import Pool from './Pool';
|
import UILink from './UILink';
|
||||||
|
|
||||||
// eslint-disable-next-line
|
export type IGroup = {
|
||||||
const SAMPLE_POOLS: Carpool.Pool[] = [
|
id: number;
|
||||||
{
|
events: IEvent[];
|
||||||
_id: '1234',
|
name: string;
|
||||||
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 default function Group() {
|
export default function Group() {
|
||||||
// eslint-disable-next-line
|
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const [error, setError] = useState(false);
|
const [loading, setLoading] = useState(true);
|
||||||
const [group, setGroup] = useState<Carpool.Group>();
|
const [group, setGroup] = useState<IGroup | null>(null);
|
||||||
const [pools, setPools] = useState<Carpool.Pool[]>([]);
|
const [events, setEvents] = useState<IEvent[]>([]);
|
||||||
const [createPoolVisible, toggleCreatePoolVisible] = useToggle(false);
|
|
||||||
|
|
||||||
const fetchPools = useCallback(() => {
|
|
||||||
makeAPIGetCall(`/groups/${id}/pools`).then((res) => {
|
|
||||||
setPools(res.data.data);
|
|
||||||
});
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
useEffect(() => fetchPools(), [fetchPools]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
makeAPIGetCall(`/groups/${id}`).then((res) => {
|
setLoading(true);
|
||||||
if ('error' in res.data) {
|
fetch('http://localhost:5000/api/groups/' + id)
|
||||||
setError(true);
|
.then((response) => response.json())
|
||||||
} else {
|
.then(setGroup)
|
||||||
setGroup(res.data.data);
|
.finally(() => setLoading(false));
|
||||||
}
|
|
||||||
});
|
fetch('http://localhost:5000/api/groups/' + id + '/events')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then(setEvents);
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
if (error) {
|
if (!group && !loading) {
|
||||||
return <h1 style={{ textAlign: 'center' }}>Group Not Found</h1>;
|
return (
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<h1>Group Not Found</h1>
|
||||||
|
<Link to="/">Home</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group) {
|
if (!group) {
|
||||||
return <h1 style={{ textAlign: 'center' }}>Loading</h1>;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { name } = group;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
textAlign: 'center',
|
||||||
display: 'flex',
|
maxWidth: '30rem',
|
||||||
flexDirection: 'column',
|
marginLeft: 'auto',
|
||||||
padding: '1rem',
|
marginRight: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h1" align="center">
|
<h1>{name}</h1>
|
||||||
{group.name}
|
<UILink href="/">Home</UILink>
|
||||||
</Typography>
|
<br />
|
||||||
|
<br />
|
||||||
<Typography variant="h3" align="center">
|
<GroupSettingsLink group={group} />
|
||||||
Pools
|
<br />
|
||||||
</Typography>
|
<EventCreatorLink group={group} />
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<br />
|
||||||
<div>
|
{events && events.length > 0 ? (
|
||||||
<Button onClick={toggleCreatePoolVisible} variant="contained">
|
<EventStream events={events} />
|
||||||
{createPoolVisible ? 'Cancel' : 'Create Pool'}
|
) : (
|
||||||
</Button>
|
<span>
|
||||||
{createPoolVisible && <CreatePool groupID={group._id} />}
|
There are no events yet. Click 'create event' above to add one!
|
||||||
</div>
|
</span>
|
||||||
{pools.map((pool, index) => (
|
)}
|
||||||
<Pool pool={pool} triggerUpdate={fetchPools} key={index} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,138 +1,34 @@
|
||||||
import Button from '@material-ui/core/Button';
|
import { useState, useEffect } from 'react';
|
||||||
import React, { useState, useEffect } from 'react';
|
import { IGroup } from './Group';
|
||||||
import Card from '@material-ui/core/Card';
|
import GroupCreatorLink from './GroupCreatorLink';
|
||||||
import CardActionArea from '@material-ui/core/CardActionArea';
|
import GroupJoinerLink from './GroupJoinerLink';
|
||||||
import CardActions from '@material-ui/core/CardActions';
|
import GroupList from './GroupList';
|
||||||
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';
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
export default function Groups() {
|
||||||
root: {
|
const [groups, setGroups] = useState<IGroup[]>([]);
|
||||||
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: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
makeAPIGetCall('/browse/groups').then((res) => {
|
fetch('http://localhost:5000/api/groups')
|
||||||
if (res.data.data) {
|
.then((res) => res.json())
|
||||||
setGroups(res.data.data);
|
.then(setGroups);
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
className=""
|
<h1>Groups</h1>
|
||||||
style={{ minHeight: '100vh', backgroundColor: '#F1EAE8' }}
|
<GroupJoinerLink />
|
||||||
>
|
<br />
|
||||||
<h1
|
<GroupCreatorLink />
|
||||||
className="d-flex justify-content-center p-4"
|
<br />
|
||||||
style={{ backgroundColor: '#F1EAE8' }}
|
{groups.length > 0 ? (
|
||||||
>
|
<GroupList groups={groups} />
|
||||||
Groups
|
) : (
|
||||||
</h1>
|
<span>
|
||||||
<Box textAlign="center">
|
You aren't in any groups. You can create your own by clicking 'create
|
||||||
<Button
|
group' above, or join one by asking an admin of the group to send you
|
||||||
variant="contained"
|
an invite link.
|
||||||
className={classes.button}
|
</span>
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
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 { useState, useEffect, useCallback } from 'react';
|
||||||
import { getPlaceDetails, PlaceDetails } from '../../api/google';
|
import { getPlaceDetails, PlaceDetails } from '../api/google';
|
||||||
import useThrottle from './useThrottle';
|
import useThrottle from './useThrottle';
|
||||||
|
|
||||||
export default function usePlace(placeId: string | null) {
|
export default function usePlace(placeId: string | null) {
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './components/NewUI/App';
|
import App from './components/App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user