wheelshare-frontend/src/components/Pool.tsx
2021-04-11 14:30:02 -04:00

233 lines
5.8 KiB
TypeScript

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 './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;
}) {
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('/comment', {
body: commentTextareaRef.current!.value,
})
.then(() => {
setCommentStatus(null);
commentTextareaRef.current!.value = '';
})
.catch(() => {
setCommentStatus('errored');
});
},
[]
);
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>
);
}