From e27f62701c780987cf304ec385996142617b60db Mon Sep 17 00:00:00 2001 From: Michael Fatemi Date: Fri, 16 Jul 2021 11:25:09 -0400 Subject: [PATCH] carpool ui revamp --- src/components/Carpool/Carpool.tsx | 46 ++++------ src/components/Carpool/CarpoolDetails.tsx | 2 +- src/components/Carpool/CarpoolTopButtons.tsx | 22 +++++ .../Carpool/CarpoolTopButtonsMembersOnly.tsx | 43 +++++++++ .../CarpoolTopButtonsNonMembersOnly.tsx | 90 ++++++++++++++++++ .../Carpool/InvitationsAndRequests.tsx | 49 ---------- src/components/Carpool/MemberList.tsx | 92 +++---------------- src/components/api.ts | 7 +- 8 files changed, 192 insertions(+), 159 deletions(-) create mode 100644 src/components/Carpool/CarpoolTopButtons.tsx create mode 100644 src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx create mode 100644 src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx delete mode 100644 src/components/Carpool/InvitationsAndRequests.tsx diff --git a/src/components/Carpool/Carpool.tsx b/src/components/Carpool/Carpool.tsx index a6b5c33..fabea95 100644 --- a/src/components/Carpool/Carpool.tsx +++ b/src/components/Carpool/Carpool.tsx @@ -1,16 +1,16 @@ -import { createContext, useCallback, useEffect, useMemo } from 'react'; +import { createContext, useCallback, useEffect } from 'react'; import { cancelCarpoolInvite, getCarpool, leaveCarpool, sendCarpoolInvite, } from '../api'; -import { useMe } from '../hooks'; import { ICarpool } from '../types'; +import UILink from '../UI/UILink'; import UISecondaryBox from '../UI/UISecondaryBox'; import useImmutable from '../useImmutable'; import CarpoolDetails from './CarpoolDetails'; -import InvitationsAndRequests from './InvitationsAndRequests'; +import CarpoolTopButtons from './CarpoolTopButtons'; import MemberList from './MemberList'; type CarpoolState = { @@ -35,13 +35,7 @@ export const CarpoolContext = createContext({ }); export default function Carpool({ id }: { id: number }) { - const [carpool, setCarpool] = useImmutable({ - id, - name: '', - event: {} as ICarpool['event'], - members: [], - invitations: {}, - }); + const [carpool, setCarpool] = useImmutable(null); useEffect(() => { getCarpool(id).then((carpool) => { @@ -78,16 +72,19 @@ export default function Carpool({ id }: { id: number }) { const cancelInvite = useCallback( (user: { id: number; name: string }) => { + if (!carpool) { + return null; + } cancelCarpoolInvite(id, user.id) .then(() => { delete carpool.invitations[user.id]; }) .catch(console.error); }, - [carpool.invitations, id] + [carpool, id] ); - const eventId = carpool.event.id; + const eventId = carpool?.event.id; const leave = useCallback(() => { if (eventId) { @@ -99,13 +96,6 @@ export default function Carpool({ id }: { id: number }) { } }, [eventId, id]); - const me = useMe(); - - const isMember = useMemo( - () => carpool.members.some((m) => m.id === me?.id), - [carpool.members, me?.id] - ); - if (!carpool) { return <>Loading...; } @@ -120,17 +110,13 @@ export default function Carpool({ id }: { id: number }) { }} > - {carpool ? ( - <> -

{carpool.name}

-

{carpool.event.name}

- {isMember && } - - - - ) : ( -

Loading

- )} +

{carpool.name}

+ + {carpool.event.name} + + + +
); diff --git a/src/components/Carpool/CarpoolDetails.tsx b/src/components/Carpool/CarpoolDetails.tsx index c2f5ed0..6c34117 100644 --- a/src/components/Carpool/CarpoolDetails.tsx +++ b/src/components/Carpool/CarpoolDetails.tsx @@ -7,7 +7,7 @@ import { CarpoolContext } from './Carpool'; export default function CarpoolDetails() { const { carpool } = useContext(CarpoolContext); return ( -
+
members.some(({ id }) => id === me?.id), + [me?.id, members] + ); + + if (isMember) { + return ; + } else { + return ; + } +} diff --git a/src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx b/src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx new file mode 100644 index 0000000..12cf484 --- /dev/null +++ b/src/components/Carpool/CarpoolTopButtonsMembersOnly.tsx @@ -0,0 +1,43 @@ +import MailOutlineIcon from '@material-ui/icons/MailOutline'; +import PersonAddIcon from '@material-ui/icons/PersonAdd'; +import EventBusyIcon from '@material-ui/icons/EventBusy'; +import { useContext } from 'react'; +import useToggle from '../useToggle'; +import { CarpoolContext } from './Carpool'; +import InvitationList from './InvitationList'; + +const spanStyle = { + padding: '0.5rem', + display: 'flex', + alignItems: 'center', + cursor: 'pointer', +}; + +export default function CarpoolTopButtonsMembersOnly() { + const [invitationsOpen, toggleInvitationsOpen] = useToggle(false); + const { leave } = useContext(CarpoolContext); + + return ( + <> +
+ + 1 request + + + Invite + + + Leave + +
+ + {invitationsOpen && } + + ); +} diff --git a/src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx b/src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx new file mode 100644 index 0000000..d828e33 --- /dev/null +++ b/src/components/Carpool/CarpoolTopButtonsNonMembersOnly.tsx @@ -0,0 +1,90 @@ +import { useCallback, useContext } from 'react'; +import { lightgrey } from '../../lib/colors'; +import { useInvitationState } from '../../state/Notifications/NotificationsHooks'; +import { NotificationsContext } from '../../state/Notifications/NotificationsProvider'; +import { useMe } from '../hooks'; +import UIButton from '../UI/UIButton'; +import { CarpoolContext } from './Carpool'; + +const defaultMe = { id: 0, name: '' }; +const greyButtonStyle = { + backgroundColor: lightgrey, + flex: 1, + margin: '0.5rem', +}; + +export default function CarpoolTopButtonsNonMembersOnly() { + const { carpool } = useContext(CarpoolContext); + const members = carpool.members; + + const { + sendCarpoolRequest, + cancelCarpoolRequest, + acceptCarpoolInvite, + denyCarpoolInvite, + } = useContext(NotificationsContext); + + const me = useMe() || defaultMe; + + const sendRequest = useCallback(() => { + sendCarpoolRequest(carpool.id); + }, [carpool.id, sendCarpoolRequest]); + + const cancelRequest = useCallback(() => { + cancelCarpoolRequest(carpool.id); + }, [carpool.id, cancelCarpoolRequest]); + + const acceptInvitation = useCallback(() => { + acceptCarpoolInvite(carpool.id).then(() => { + members.push(me); + }); + }, [acceptCarpoolInvite, carpool.id, members, me]); + + const denyInvitation = useCallback(() => { + denyCarpoolInvite(carpool.id).then(() => { + members.push(me); + }); + }, [carpool.id, denyCarpoolInvite, me, members]); + + const invitationState = useInvitationState(carpool.id); + return ( + <> + {invitationState === 'requested' ? ( + + Cancel request to join + + ) : invitationState === 'none' ? ( + + Request to join + + ) : ( + <> + + You've been invited to this carpool! + +
+ + Accept + + + Decline + +
+ + )} + + ); +} diff --git a/src/components/Carpool/InvitationsAndRequests.tsx b/src/components/Carpool/InvitationsAndRequests.tsx deleted file mode 100644 index 5253049..0000000 --- a/src/components/Carpool/InvitationsAndRequests.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { lightgrey } from '../../lib/colors'; -import UIButton from '../UI/UIButton'; -import InvitationList from './InvitationList'; -import MailOutlineIcon from '@material-ui/icons/MailOutline'; -import PersonAddIcon from '@material-ui/icons/PersonAdd'; -import useToggle from '../useToggle'; - -export default function InvitationsAndRequests() { - const [invitationsOpen, toggleInvitationsOpen] = useToggle(false); - - return ( - <> -
- {/* Requests */} - - 1 request - - {/* Invitations */} - - Invite - -
- - {invitationsOpen && } - - ); -} diff --git a/src/components/Carpool/MemberList.tsx b/src/components/Carpool/MemberList.tsx index 559ff5d..4439db3 100644 --- a/src/components/Carpool/MemberList.tsx +++ b/src/components/Carpool/MemberList.tsx @@ -1,12 +1,5 @@ import AccountCircleIcon from '@material-ui/icons/AccountCircle'; -import { useCallback } from 'react'; -import { useMemo } from 'react'; import { useContext } from 'react'; -import { useInvitationState } from '../../state/Notifications/NotificationsHooks'; -import { NotificationsContext } from '../../state/Notifications/NotificationsProvider'; -import { lightgrey } from '../../lib/colors'; -import { useMe } from '../hooks'; -import UIButton from '../UI/UIButton'; import { CarpoolContext } from './Carpool'; function MemberRow({ member }: { member: { id: number; name: string } }) { @@ -18,50 +11,26 @@ function MemberRow({ member }: { member: { id: number; name: string } }) { ); } +function formatOthers(hiddenMemberCount: number) { + if (hiddenMemberCount === 0) { + return ''; + } + + if (hiddenMemberCount === 1) { + return '1 other...'; + } + + return `${hiddenMemberCount} others...`; +} + const shownMembersCount = 2; -const defaultMe = { id: 0, name: '' }; - export default function MemberList() { - const { leave, carpool } = useContext(CarpoolContext); + const { carpool } = useContext(CarpoolContext); const members = carpool.members; const membersToShow = members.slice(0, shownMembersCount); const hiddenMemberCount = members.length - membersToShow.length; - const { - sendCarpoolRequest, - cancelCarpoolRequest, - acceptCarpoolInvite, - denyCarpoolInvite, - } = useContext(NotificationsContext); - const invitationState = useInvitationState(carpool.id); - - const me = useMe() || defaultMe; - - const sendRequest = useCallback(() => { - sendCarpoolRequest(carpool.id); - }, [carpool.id, sendCarpoolRequest]); - - const cancelRequest = useCallback(() => { - cancelCarpoolRequest(carpool.id); - }, [carpool.id, cancelCarpoolRequest]); - - const acceptInvitation = useCallback(() => { - acceptCarpoolInvite(carpool.id).then(() => { - members.push(me); - }); - }, [acceptCarpoolInvite, carpool.id, members, me]); - - const denyInvitation = useCallback(() => { - denyCarpoolInvite(carpool.id).then(() => { - members.push(me); - }); - }, [carpool.id, denyCarpoolInvite, me, members]); - - const isMember = useMemo(() => { - return members.some(({ id }) => id === me?.id); - }, [me?.id, members]); - return (
-

Members

+

Members

{members.length > 0 ? (
{membersToShow.map((member) => ( ))} - {hiddenMemberCount > 0 && - (hiddenMemberCount === 1 - ? hiddenMemberCount + ' other...' - : hiddenMemberCount + ' others...')} + {formatOthers(hiddenMemberCount)}
) : ( 'This carpool has no members.' )} - - {isMember ? ( - - Leave - - ) : invitationState === 'requested' ? ( - Cancel request to join - ) : invitationState === 'none' ? ( - Request to join - ) : ( - - You've been invited to this carpool! -
- - Accept - - - Deny - -
-
- )}
); } diff --git a/src/components/api.ts b/src/components/api.ts index 9c7bc76..f64ca0e 100644 --- a/src/components/api.ts +++ b/src/components/api.ts @@ -123,8 +123,11 @@ export async function getGroups(): Promise { return await get('/groups'); } -export async function deleteGroup(id: number) { - await delete$('/groups/' + id); +export async function deleteGroup( + id: number +): Promise<{ status: 'success' | 'error' }> { + const { status } = await delete$('/groups/' + id); + return { status }; } export async function createGroup(name: string): Promise<{ id: number }> {