mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-18 18:10:16 -04:00
183 lines
4.7 KiB
TypeScript
183 lines
4.7 KiB
TypeScript
import * as immutable from 'immutable';
|
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
import { green, lightgrey } from '../../lib/colors';
|
|
import {
|
|
addOrUpdateEventSignup,
|
|
getEvent,
|
|
getEventSignups,
|
|
removeEventSignup,
|
|
} from '../api';
|
|
import { useMe } from '../hooks';
|
|
import { IEvent, IEventSignup } from '../types';
|
|
import UIButton from '../UI/UIButton';
|
|
import UILink from '../UI/UILink';
|
|
import UIPlacesAutocomplete from '../UI/UIPlacesAutocomplete';
|
|
import UISecondaryBox from '../UI/UISecondaryBox';
|
|
import UISecondaryHeader from '../UI/UISecondaryHeader';
|
|
import useThrottle from '../useThrottle';
|
|
import EventCarpools from './EventCarpools';
|
|
import EventContext from './EventContext';
|
|
import EventDetails from './EventDetails';
|
|
import EventSignups from './EventSignups';
|
|
|
|
function GroupName({ group }: { group: IEvent['group'] }) {
|
|
return <UILink href={`/groups/${group.id}`}>{group.name}</UILink>;
|
|
}
|
|
|
|
export default function Event({
|
|
id,
|
|
initial,
|
|
}: {
|
|
id: number;
|
|
initial?: IEvent;
|
|
}) {
|
|
const [event, setEvent] = useState<IEvent | null>(initial || null);
|
|
const [placeId, setPlaceId] = useState<string | null>(null);
|
|
const [interested, setInterested] = useState(false);
|
|
const [updating, setUpdating] = useState(false);
|
|
const [signups, setSignups] = useState<IEventSignup[] | null>(null);
|
|
const [hasCarpool, setHasCarpool] = useState(false);
|
|
const toggleInterested = useCallback(() => setInterested((i) => !i), []);
|
|
const toggleInterestedThrottled = useThrottle(toggleInterested, 500);
|
|
const existingSignup = useRef({
|
|
interested: false,
|
|
placeId: null as string | null,
|
|
eventId: null as number | null,
|
|
});
|
|
const me = useMe();
|
|
|
|
const [tentativeInvites, setTentativeInvites] = useState(
|
|
immutable.Set<number>()
|
|
);
|
|
|
|
const addTentativeInvite = useCallback((userId: number) => {
|
|
setTentativeInvites((t) => t.add(userId));
|
|
}, []);
|
|
|
|
const removeTentativeInvite = useCallback((userId: number) => {
|
|
setTentativeInvites((t) => t.delete(userId));
|
|
}, []);
|
|
|
|
const refresh = useCallback(() => {
|
|
getEvent(id).then(setEvent);
|
|
}, [id]);
|
|
|
|
useEffect(refresh, [refresh]);
|
|
|
|
useEffect(() => {
|
|
if (signups === null) {
|
|
return;
|
|
}
|
|
|
|
const removeSignup = () => {
|
|
if (prev.interested) {
|
|
removeEventSignup(id)
|
|
.then(() => {
|
|
prev.interested = false;
|
|
})
|
|
.finally(() => setUpdating(false));
|
|
}
|
|
};
|
|
|
|
const addOrUpdateSignup = () => {
|
|
if (!prev.interested || prev.placeId !== placeId) {
|
|
console.log('Adding or updating signup.', prev, {
|
|
interested,
|
|
placeId,
|
|
eventId: id,
|
|
signups,
|
|
});
|
|
addOrUpdateEventSignup(id, placeId)
|
|
.then(() => {
|
|
prev.placeId = placeId;
|
|
prev.eventId = id;
|
|
prev.interested = true;
|
|
})
|
|
.finally(() => setUpdating(false));
|
|
}
|
|
};
|
|
|
|
const prev = existingSignup.current;
|
|
|
|
if (!interested) {
|
|
removeSignup();
|
|
} else {
|
|
addOrUpdateSignup();
|
|
}
|
|
}, [id, interested, placeId, signups, updating]);
|
|
|
|
useEffect(() => {
|
|
getEventSignups(id)
|
|
.then((signups) => {
|
|
for (let signup of signups) {
|
|
if (signup.user.id === me?.id) {
|
|
setInterested(true);
|
|
setPlaceId(signup.placeId);
|
|
existingSignup.current.eventId = id;
|
|
existingSignup.current.placeId = signup.placeId;
|
|
existingSignup.current.interested = true;
|
|
}
|
|
}
|
|
setSignups(signups);
|
|
})
|
|
.catch(console.error);
|
|
}, [id, me?.id]);
|
|
|
|
if (!event) {
|
|
return <UISecondaryBox>Loading...</UISecondaryBox>;
|
|
}
|
|
|
|
const { name, group, formattedAddress, startTime, endTime } = event;
|
|
|
|
return (
|
|
<EventContext.Provider
|
|
value={{
|
|
event,
|
|
refresh,
|
|
default: false,
|
|
addTentativeInvite,
|
|
removeTentativeInvite,
|
|
tentativeInvites,
|
|
signups,
|
|
hasCarpool,
|
|
setHasCarpool,
|
|
}}
|
|
>
|
|
<UISecondaryBox>
|
|
<div style={{ textAlign: 'center' }}>
|
|
<UISecondaryHeader>{name}</UISecondaryHeader>
|
|
<GroupName group={group} />
|
|
</div>
|
|
<EventDetails {...{ startTime, endTime, formattedAddress }} />
|
|
<UIButton
|
|
onClick={toggleInterestedThrottled}
|
|
style={{
|
|
backgroundColor: interested ? green : lightgrey,
|
|
color: interested ? 'white' : 'black',
|
|
transition: 'color 0.2s, background-color 0.2s',
|
|
}}
|
|
>
|
|
{interested ? 'Interested' : 'Not interested'}
|
|
</UIButton>
|
|
{interested && (
|
|
<>
|
|
<UIPlacesAutocomplete
|
|
placeholder="Pickup and dropoff location"
|
|
onSelected={(_address, placeID) => {
|
|
setPlaceId(placeID);
|
|
}}
|
|
style={placeId != null ? { border: '2px solid ' + green } : {}}
|
|
placeId={placeId}
|
|
/>
|
|
<br />
|
|
<EventCarpools />
|
|
{signups !== null && (
|
|
<EventSignups myPlaceId={placeId} signups={signups} />
|
|
)}
|
|
</>
|
|
)}
|
|
</UISecondaryBox>
|
|
</EventContext.Provider>
|
|
);
|
|
}
|