use immutable for Carpools

This commit is contained in:
Michael Fatemi 2021-07-15 07:32:40 -04:00
parent 9d34b89ffe
commit 3a761ffc8b
4 changed files with 75 additions and 43 deletions

View File

@ -1,5 +1,11 @@
import { useMemo } from 'react'; import * as immutable from 'immutable';
import { createContext, useCallback, useEffect, useState } from 'react'; import {
createContext,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { import {
cancelCarpoolInvite, cancelCarpoolInvite,
getCarpool, getCarpool,
@ -7,14 +13,33 @@ import {
sendCarpoolInvite, sendCarpoolInvite,
} from '../api'; } from '../api';
import { useMe } from '../hooks'; import { useMe } from '../hooks';
import { ICarpool } from '../types';
import UISecondaryBox from '../UI/UISecondaryBox'; import UISecondaryBox from '../UI/UISecondaryBox';
import CarpoolDetails from './CarpoolDetails'; import CarpoolDetails from './CarpoolDetails';
import InvitationsAndRequests from './InvitationsAndRequests'; import InvitationsAndRequests from './InvitationsAndRequests';
import MemberList from './MemberList'; import MemberList from './MemberList';
class CarpoolState extends immutable.Record({
id: 0,
name: '',
eventId: -1,
event: {
id: -1,
name: '',
formattedAddress: '',
latitude: 0,
longitude: 0,
placeId: '',
},
members: immutable.List<{ id: number; name: string }>(),
invitations:
immutable.Map<
number,
{ isRequest: boolean; user: { id: number; name: string } }
>(),
}) {}
export const CarpoolContext = createContext({ export const CarpoolContext = createContext({
carpool: null! as ICarpool, carpool: new CarpoolState(),
sendInvite: (user: { id: number; name: string }) => { sendInvite: (user: { id: number; name: string }) => {
console.error('not implemented: sendInvite'); console.error('not implemented: sendInvite');
}, },
@ -27,10 +52,23 @@ export const CarpoolContext = createContext({
}); });
export default function Carpool({ id }: { id: number }) { export default function Carpool({ id }: { id: number }) {
const [carpool, setCarpool] = useState<ICarpool | null>(null); const [carpool, setCarpool] = useState(new CarpoolState());
useEffect(() => { useEffect(() => {
getCarpool(id).then(setCarpool); getCarpool(id).then((carpool) => {
setCarpool(
new CarpoolState({
id: carpool.id,
name: carpool.name,
eventId: carpool.eventId || carpool.event.id,
event: carpool.event,
members: immutable.List(carpool.members),
invitations: immutable.Map(
carpool.invitations.map((invite) => [invite.user.id, invite])
),
})
);
});
}, [id]); }, [id]);
const sendInvite = useCallback( const sendInvite = useCallback(
@ -38,15 +76,11 @@ export default function Carpool({ id }: { id: number }) {
if (carpool) { if (carpool) {
sendCarpoolInvite(id, user.id) sendCarpoolInvite(id, user.id)
.then(() => { .then(() => {
setCarpool( setCarpool((carpool) =>
(carpool) => carpool.set(
carpool && { 'invitations',
...carpool, carpool.invitations.set(user.id, { isRequest: false, user })
invitations: [ )
...carpool.invitations,
{ isRequest: false, user },
],
}
); );
}) })
.catch(console.error); .catch(console.error);
@ -78,7 +112,7 @@ export default function Carpool({ id }: { id: number }) {
[id] [id]
); );
const eventId = carpool?.eventId; const eventId = carpool.eventId;
const leave = useCallback(() => { const leave = useCallback(() => {
if (eventId) { if (eventId) {
@ -93,8 +127,8 @@ export default function Carpool({ id }: { id: number }) {
const me = useMe(); const me = useMe();
const isMember = useMemo( const isMember = useMemo(
() => carpool?.members.some((m) => m.id === me?.id), () => carpool.members.some((m) => m.id === me?.id),
[carpool?.members, me?.id] [carpool.members, me?.id]
); );
if (!carpool) { if (!carpool) {
@ -116,8 +150,8 @@ export default function Carpool({ id }: { id: number }) {
<h1 style={{ marginBottom: '0rem' }}>{carpool.name}</h1> <h1 style={{ marginBottom: '0rem' }}>{carpool.name}</h1>
<h2 style={{ marginBottom: '0rem' }}>{carpool.event.name}</h2> <h2 style={{ marginBottom: '0rem' }}>{carpool.event.name}</h2>
{isMember && <InvitationsAndRequests />} {isMember && <InvitationsAndRequests />}
<CarpoolDetails carpool={carpool} /> <CarpoolDetails />
<MemberList members={carpool.members} /> <MemberList />
</> </>
) : ( ) : (
<h2>Loading</h2> <h2>Loading</h2>

View File

@ -1,9 +1,11 @@
import EventIcon from '@material-ui/icons/Event'; import EventIcon from '@material-ui/icons/Event';
import LocationOnIcon from '@material-ui/icons/LocationOn'; import LocationOnIcon from '@material-ui/icons/LocationOn';
import { useContext } from 'react';
import { ICarpool } from '../types'; import { CarpoolContext } from './Carpool';
export default function CarpoolDetails({ carpool }: { carpool: ICarpool }) { export default function CarpoolDetails() {
const { carpool } = useContext(CarpoolContext);
return ( return (
<div style={{ fontSize: '1.5rem', fontWeight: 400 }}> <div style={{ fontSize: '1.5rem', fontWeight: 400 }}>
<div <div

View File

@ -61,6 +61,7 @@ export default function InvitationList() {
new Set( new Set(
carpool.invitations carpool.invitations
.filter((invitation) => !invitation.isRequest) .filter((invitation) => !invitation.isRequest)
.valueSeq()
.map((invitation) => invitation.user.id) .map((invitation) => invitation.user.id)
), ),
[carpool.invitations] [carpool.invitations]
@ -68,11 +69,9 @@ export default function InvitationList() {
const availableSignupsAlreadyInvited = useMemo( const availableSignupsAlreadyInvited = useMemo(
() => () =>
availableSignups availableSignups?.filter((signup) =>
? availableSignups.filter((signup) => invitedUserIDs.has(signup.user.id)
invitedUserIDs.has(signup.user.id) ) ?? null,
)
: null,
[availableSignups, invitedUserIDs] [availableSignups, invitedUserIDs]
); );

View File

@ -18,22 +18,13 @@ function MemberRow({ member }: { member: { id: number; name: string } }) {
); );
} }
export default function MemberList({ const shownMembersCount = 2;
members,
}: {
members: {
id: number;
name: string;
}[];
}) {
const { leave, carpool } = useContext(CarpoolContext);
const membersToShow = members.slice(0, 2);
const hiddenMemberCount = members.length - membersToShow.length;
const me = useMe()!;
const isMember = useMemo(() => { export default function MemberList() {
return members.some(({ id }) => id === me.id); const { leave, carpool } = useContext(CarpoolContext);
}, [me.id, members]); const members = carpool.members;
const membersToShow = members.slice(0, shownMembersCount);
const hiddenMemberCount = members.size - membersToShow.size;
const { sendCarpoolRequest, cancelCarpoolRequest } = const { sendCarpoolRequest, cancelCarpoolRequest } =
useContext(NotificationsContext); useContext(NotificationsContext);
@ -47,6 +38,12 @@ export default function MemberList({
cancelCarpoolRequest(carpool.id); cancelCarpoolRequest(carpool.id);
}, [carpool.id, cancelCarpoolRequest]); }, [carpool.id, cancelCarpoolRequest]);
const me = useMe()!;
const isMember = useMemo(() => {
return members.some(({ id }) => id === me?.id);
}, [me?.id, members]);
return ( return (
<div <div
style={{ style={{
@ -57,7 +54,7 @@ export default function MemberList({
}} }}
> >
<h3 style={{ marginBlockEnd: '0' }}>Members</h3> <h3 style={{ marginBlockEnd: '0' }}>Members</h3>
{members.length > 0 ? ( {members.size > 0 ? (
<div style={{ display: 'flex', flexDirection: 'column' }}> <div style={{ display: 'flex', flexDirection: 'column' }}>
{membersToShow.map((member) => ( {membersToShow.map((member) => (
<MemberRow member={member} key={member.id} /> <MemberRow member={member} key={member.id} />