diff --git a/src/components/Event/Event.tsx b/src/components/Event/Event.tsx index 871b917..ee0d744 100644 --- a/src/components/Event/Event.tsx +++ b/src/components/Event/Event.tsx @@ -33,7 +33,24 @@ export default function Event({ id: number; initial?: IEvent; }) { - const [event, setEvent] = useState(initial || null); + const [event, setEvent] = useImmutable({ + id, + name: '', + group: { + id: 0, + name: '', + }, + carpools: [], + startTime: '', + endTime: '', + daysOfWeek: 0, + placeId: '', + formattedAddress: '', + latitude: 0, + longitude: 0, + duration: 0, + ...(initial || {}), + }); const [myPlaceId, setPlaceId] = useState(null); const [interested, setInterested] = useState(false); const [updating, setUpdating] = useState(false); @@ -53,7 +70,7 @@ export default function Event({ const refresh = useCallback(() => { getEvent(id).then(setEvent); - }, [id]); + }, [id, setEvent]); useEffect(refresh, [refresh]); diff --git a/src/components/Event/EventCarpoolCreateButton.tsx b/src/components/Event/EventCarpoolCreateButton.tsx new file mode 100644 index 0000000..f945561 --- /dev/null +++ b/src/components/Event/EventCarpoolCreateButton.tsx @@ -0,0 +1,121 @@ +import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { lightgrey } from '../../lib/colors'; +import { createCarpool } from '../api'; +import { useMe } from '../hooks'; +import UIButton from '../UI/UIButton'; +import UILink from '../UI/UILink'; +import EventContext from './EventContext'; + +type CreationStatus = null | 'pending' | 'completed' | 'errored'; + +export default function EventCarpoolCreateButton() { + const { event, setHasCarpool, tentativeInvites, signups } = + useContext(EventContext); + + const [creationStatus, setCreationStatus] = useState(null); + const [createdCarpoolId, setCreatedCarpoolId] = useState(null); + + const me = useMe()!; + const myCarpool = useMemo( + () => + event.carpools.find((carpool) => + carpool.members.some((member) => member.id === me.id) + ), + [event.carpools, me.id] + ); + const alreadyInCarpool = + myCarpool !== undefined || creationStatus === 'completed'; + + useEffect(() => { + setHasCarpool(alreadyInCarpool); + }, [alreadyInCarpool, setHasCarpool]); + + const createCarpoolCallback = useCallback(() => { + setCreationStatus('pending'); + + createCarpool({ + name: me.name + "'s Carpool", + eventId: event.id, + invitedUserIds: Object.keys(tentativeInvites).map(Number), + }) + .then(({ id }) => { + setCreatedCarpoolId(id); + event.carpools.push({ + id, + name: me.name + "'s Carpool", + members: [{ id: me.id, name: me.name }], + }); + setCreationStatus('completed'); + }) + .catch(() => { + setCreationStatus('errored'); + }); + }, [event.carpools, event.id, me.id, me.name, tentativeInvites]); + + const tentativeInviteNames = useMemo(() => { + if (!signups) return []; + const names = Object.keys(tentativeInvites).map((id) => { + const signup = signups[id]; + return signup?.user.name; + }); + return names.filter((n) => n != null); + }, [tentativeInvites, signups]); + + let createCarpoolSection; + + if (tentativeInviteNames.length > 0) { + const inviteeCount = tentativeInviteNames.length; + const peoplePlural = inviteeCount > 1 ? 'People' : 'Person'; + createCarpoolSection = ( + <> +
+ List: +
+ {tentativeInviteNames.join(',')} + + {creationStatus === null + ? `Create Carpool With ${inviteeCount} ${peoplePlural}` + : creationStatus === 'pending' + ? 'Creating...' + : 'Errored'} + + + ); + } else + createCarpoolSection = ( + <> + Available to drive? + + {creationStatus === null + ? 'Create Empty Carpool' + : creationStatus === 'pending' + ? 'Creating...' + : 'Errored'} + + + ); + + return ( +
+ {creationStatus === 'completed' ? ( + + Created{' '} + your carpool! + + ) : myCarpool ? ( + + You are already in a carpool for this event:{' '} + {myCarpool.name} + + ) : ( + createCarpoolSection + )} +
+ ); +} diff --git a/src/components/Event/EventCarpools.tsx b/src/components/Event/EventCarpools.tsx index 90c46b5..12fd5fe 100644 --- a/src/components/Event/EventCarpools.tsx +++ b/src/components/Event/EventCarpools.tsx @@ -1,19 +1,15 @@ import CancelIcon from '@material-ui/icons/Cancel'; import CheckIcon from '@material-ui/icons/Check'; import EmojiPeopleIcon from '@material-ui/icons/EmojiPeople'; -import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; -import { lightgrey } from '../../lib/colors'; +import { useCallback, useContext, useMemo } from 'react'; import { Location } from '../../lib/estimateoptimalpath'; import { useCancelCarpoolRequest, useInvitationState, useSendCarpoolRequest, } from '../../state/Notifications/NotificationsHooks'; -import { createCarpool } from '../api'; import { useMe } from '../hooks'; import { IEvent } from '../types'; -import UIButton from '../UI/UIButton'; -import UILink from '../UI/UILink'; import useOptimalPath from '../useOptimalPath'; import usePlace from '../usePlace'; import EventContext from './EventContext'; @@ -138,110 +134,22 @@ function CarpoolRow({ ); } -type CreationStatus = null | 'pending' | 'completed' | 'errored'; - export default function Carpools() { - const { event, tentativeInvites, signups, setHasCarpool } = - useContext(EventContext); - const [creationStatus, setCreationStatus] = useState(null); - const [createdCarpoolId, setCreatedCarpoolId] = useState(null); + const { event } = useContext(EventContext); - const me = useMe()!; - const myCarpool = useMemo( + const myId = useMe()?.id; + + const alreadyInCarpool = useMemo( () => - event.carpools.find((carpool) => - carpool.members.some((member) => member.id === me.id) + event.carpools.some((carpool) => + carpool.members.some((member) => member.id === myId) ), - [event.carpools, me.id] + [event.carpools, myId] ); - const alreadyInCarpool = - myCarpool !== undefined || creationStatus === 'completed'; - - useEffect(() => { - setHasCarpool(alreadyInCarpool); - }, [alreadyInCarpool, setHasCarpool]); - - const createCarpoolCallback = useCallback(() => { - setCreationStatus('pending'); - - createCarpool({ - name: me.name + "'s Carpool", - eventId: event.id, - invitedUserIds: Object.keys(tentativeInvites).map(Number), - }) - .then(({ id }) => { - setCreatedCarpoolId(id); - setCreationStatus('completed'); - }) - .catch(() => { - setCreationStatus('errored'); - }); - }, [event.id, me.name, tentativeInvites]); - - const tentativeInviteNames = useMemo(() => { - if (!signups) return []; - const names = Object.keys(tentativeInvites).map((id) => { - const signup = signups[id]; - return signup?.user.name; - }); - return names.filter((n) => n != null); - }, [tentativeInvites, signups]); - - let createCarpoolSection; - - if (tentativeInviteNames.length > 0) { - const inviteeCount = tentativeInviteNames.length; - const peoplePlural = inviteeCount > 1 ? 'People' : 'Person'; - createCarpoolSection = ( - <> -
- You have invited these people to carpool with you: - {tentativeInviteNames.join(',')} - - {creationStatus === null - ? `Create Carpool With ${inviteeCount} ${peoplePlural}` - : creationStatus === 'pending' - ? 'Creating...' - : 'Errored'} - - - ); - } else - createCarpoolSection = ( - <> - Available to drive? - - {creationStatus === null - ? 'Create Empty Carpool' - : creationStatus === 'pending' - ? 'Creating...' - : 'Errored'} - - - ); return (

Carpools

- {creationStatus === 'completed' ? ( - - Created{' '} - your carpool! - - ) : myCarpool ? ( - - You are already in a carpool for this event:{' '} - {myCarpool.name} - - ) : ( - createCarpoolSection - )} {event.carpools.map((carpool) => (

People without a carpool

+ {signupsWithoutCarpool.map((signup) => ( ( }; } else if (typeof target[property] === 'function') { return function () { - console.log(target[property]); // @ts-ignore return target[property].apply(target, arguments); };