diff --git a/src/components/Event/Event.tsx b/src/components/Event/Event.tsx index 9b6092e..98703ad 100644 --- a/src/components/Event/Event.tsx +++ b/src/components/Event/Event.tsx @@ -1,10 +1,11 @@ import { useCallback, useEffect, useRef, useState } from 'react'; +import { green, lightgrey } from '../../lib/colors'; import { addOrUpdateEventSignup, + getEvent, getEventSignups, removeEventSignup, } from '../api'; -import { green, lightgrey } from '../../lib/colors'; import { useMe } from '../hooks'; import { IEvent, IEventSignup } from '../types'; import UIButton from '../UI/UIButton'; @@ -14,6 +15,7 @@ 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'; @@ -21,8 +23,14 @@ function GroupName({ group }: { group: IEvent['group'] }) { return {group.name}; } -export default function Event({ event }: { event: IEvent }) { - const { name, group, formattedAddress, startTime, endTime } = event; +export default function Event({ + id, + initial, +}: { + id: number; + initial?: IEvent; +}) { + const [event, setEvent] = useState(initial || null); const [placeId, setPlaceId] = useState(null); const [interested, setInterested] = useState(false); const [updating, setUpdating] = useState(false); @@ -36,6 +44,12 @@ export default function Event({ event }: { event: IEvent }) { }); const me = useMe(); + const refresh = useCallback(() => { + getEvent(id).then(setEvent); + }, [id]); + + useEffect(refresh, [refresh]); + useEffect(() => { if (signups === null) { return; @@ -43,7 +57,7 @@ export default function Event({ event }: { event: IEvent }) { const removeSignup = () => { if (prev.interested) { - removeEventSignup(event.id) + removeEventSignup(id) .then(() => { prev.interested = false; }) @@ -56,13 +70,13 @@ export default function Event({ event }: { event: IEvent }) { console.log('Adding or updating signup.', prev, { interested, placeId, - eventId: event.id, + eventId: id, signups, }); - addOrUpdateEventSignup(event.id, placeId) + addOrUpdateEventSignup(id, placeId) .then(() => { prev.placeId = placeId; - prev.eventId = event.id; + prev.eventId = id; prev.interested = true; }) .finally(() => setUpdating(false)); @@ -76,16 +90,16 @@ export default function Event({ event }: { event: IEvent }) { } else { addOrUpdateSignup(); } - }, [event.id, interested, placeId, signups, updating]); + }, [id, interested, placeId, signups, updating]); useEffect(() => { - getEventSignups(event.id) + getEventSignups(id) .then((signups) => { for (let signup of signups) { if (signup.user.id === me?.id) { setInterested(true); setPlaceId(signup.placeId); - existingSignup.current.eventId = event.id; + existingSignup.current.eventId = id; existingSignup.current.placeId = signup.placeId; existingSignup.current.interested = true; } @@ -93,42 +107,54 @@ export default function Event({ event }: { event: IEvent }) { setSignups(signups); }) .catch(console.error); - }, [event.id, me?.id]); + }, [id, me?.id]); + + if (!event) { + return Loading...; + } + + const { name, group, formattedAddress, startTime, endTime } = event; return ( - -
- {name} - -
- - - {interested ? 'Interested' : 'Not interested'} - - {interested && ( - <> - { - setPlaceId(placeID); - }} - style={placeId != null ? { border: '2px solid ' + green } : {}} - placeId={placeId} - /> -
- - {signups !== null && ( - - )} - - )} -
+ + +
+ {name} + +
+ + + {interested ? 'Interested' : 'Not interested'} + + {interested && ( + <> + { + setPlaceId(placeID); + }} + style={placeId != null ? { border: '2px solid ' + green } : {}} + placeId={placeId} + /> +
+ + {signups !== null && ( + + )} + + )} +
+
); } diff --git a/src/components/Event/EventCarpools.tsx b/src/components/Event/EventCarpools.tsx index f4418d9..09d2068 100644 --- a/src/components/Event/EventCarpools.tsx +++ b/src/components/Event/EventCarpools.tsx @@ -1,15 +1,41 @@ -// import CallMergeIcon from '@material-ui/icons/CallMerge'; +import CancelIcon from '@material-ui/icons/Cancel'; +import CheckIcon from '@material-ui/icons/Check'; import EmojiPeopleIcon from '@material-ui/icons/EmojiPeople'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useContext, useMemo, useState } from 'react'; import { createCarpool } from '../api'; import { lightgrey } from '../../lib/colors'; import { useMe } from '../hooks'; import { IEvent } from '../types'; import UIButton from '../UI/UIButton'; import UILink from '../UI/UILink'; +import EventContext from './EventContext'; +import { + useCancelCarpoolRequest, + useInvitationState, + useSendCarpoolRequest, +} from '../../state/Notifications/NotificationsHooks'; -function CarpoolRow({ carpool }: { carpool: IEvent['carpools'][0] }) { +function CarpoolRow({ + carpool, + inCarpoolAlready, +}: { + carpool: IEvent['carpools'][0]; + inCarpoolAlready: boolean; +}) { const PADDING = '1rem'; + const inviteState = useInvitationState(carpool.id); + + const cancelCarpoolRequest = useCancelCarpoolRequest(); + const sendCarpoolRequest = useSendCarpoolRequest(); + + const sendButton = useCallback(() => { + sendCarpoolRequest(carpool.id); + }, [sendCarpoolRequest, carpool.id]); + + const cancelButton = useCallback(() => { + cancelCarpoolRequest(carpool.id); + }, [cancelCarpoolRequest, carpool.id]); + return (
{carpool.extraDistance} miles
*/} {/* */} - + {!inCarpoolAlready && ( + <> + {inviteState === 'none' ? ( + + ) : inviteState === 'requested' ? ( + + ) : ( + // inviteState === 'invited + + )} + + )} ); } type CreationStatus = null | 'pending' | 'completed' | 'errored'; -export default function Carpools({ event }: { event: IEvent }) { +export default function Carpools() { + const { event } = useContext(EventContext); const [creationStatus, setCreationStatus] = useState(null); const [createdCarpoolId, setCreatedCarpoolId] = useState(null); @@ -59,7 +103,8 @@ export default function Carpools({ event }: { event: IEvent }) { ), [event.carpools, me.id] ); - const alreadyInCarpool = myCarpool !== undefined; + const alreadyInCarpool = + myCarpool !== undefined || creationStatus === 'completed'; const createEmptyCarpool = useCallback(() => { setCreationStatus('pending'); @@ -107,7 +152,11 @@ export default function Carpools({ event }: { event: IEvent }) { )} {event.carpools.map((carpool) => ( - + ))} ); diff --git a/src/components/Event/EventContext.tsx b/src/components/Event/EventContext.tsx new file mode 100644 index 0000000..40633da --- /dev/null +++ b/src/components/Event/EventContext.tsx @@ -0,0 +1,12 @@ +import { createContext } from 'react'; +import { IEvent } from '../types'; + +const EventContext = createContext({ + refresh: () => { + console.error('not implemented: refresh'); + }, + event: null! as IEvent, + default: true, +}); + +export default EventContext; diff --git a/src/components/Event/EventPage.tsx b/src/components/Event/EventPage.tsx index 2cd8865..42a4e04 100644 --- a/src/components/Event/EventPage.tsx +++ b/src/components/Event/EventPage.tsx @@ -16,7 +16,7 @@ export default function EventPage() { return ( <>
- {event ? : Loading...} + {event ? : Loading...} ); } diff --git a/src/components/EventStream.tsx b/src/components/EventStream.tsx index c394463..4f8b67a 100644 --- a/src/components/EventStream.tsx +++ b/src/components/EventStream.tsx @@ -5,7 +5,7 @@ export default function EventStream({ events }: { events: IEvent[] }) { return (
{events.map((event) => ( - + ))}
); diff --git a/src/state/Notifications/NotificationsHooks.tsx b/src/state/Notifications/NotificationsHooks.tsx index 5959238..dbb3f70 100644 --- a/src/state/Notifications/NotificationsHooks.tsx +++ b/src/state/Notifications/NotificationsHooks.tsx @@ -2,6 +2,14 @@ import { useMemo } from 'react'; import { useContext } from 'react'; import { NotificationsContext } from './NotificationsProvider'; +export function useSendCarpoolRequest() { + return useContext(NotificationsContext).sendCarpoolRequest; +} + +export function useCancelCarpoolRequest() { + return useContext(NotificationsContext).cancelCarpoolRequest; +} + export function useInvitationState( carpoolId: number ): 'invited' | 'requested' | 'none' {