diff --git a/src/components/App.tsx b/src/components/App.tsx index 7afd553..567cf3e 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,8 +1,8 @@ import { CSSProperties, lazy, Suspense } from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; -import GroupsProvider from '../state/GroupsProvider'; import NotificationsProvider from '../state/Notifications/NotificationsProvider'; import { useMe } from './hooks'; +import UseImmutableTest from './UseImmutableTest'; import WheelShare from './WheelShare'; import WheelShareLoggedOut from './WheelShareLoggedOut'; @@ -26,30 +26,29 @@ export default function App() { return ( - -
-
- - +
+ +
+ + + + - - - - - - - - -
+ + + + + +
- +
); } diff --git a/src/components/Carpool/MemberList.tsx b/src/components/Carpool/MemberList.tsx index adf5859..ef7296b 100644 --- a/src/components/Carpool/MemberList.tsx +++ b/src/components/Carpool/MemberList.tsx @@ -38,7 +38,7 @@ export default function MemberList() { cancelCarpoolRequest(carpool.id); }, [carpool.id, cancelCarpoolRequest]); - const me = useMe()!; + const me = useMe() || { id: 0, name: '' }; const isMember = useMemo(() => { return members.some(({ id }) => id === me?.id); diff --git a/src/components/Event/Event.tsx b/src/components/Event/Event.tsx index 766db62..d1fb3e4 100644 --- a/src/components/Event/Event.tsx +++ b/src/components/Event/Event.tsx @@ -46,7 +46,7 @@ export default function Event({ ...(initial || {}), }); - const me = useMe()!; + const me = useMe() || { id: 0, name: '' }; const [tentativeInvites] = useImmutable>({}); diff --git a/src/components/Event/EventCarpoolCreateButton.tsx b/src/components/Event/EventCarpoolCreateButton.tsx index 66b4469..ade65d4 100644 --- a/src/components/Event/EventCarpoolCreateButton.tsx +++ b/src/components/Event/EventCarpoolCreateButton.tsx @@ -15,7 +15,7 @@ export default function EventCarpoolCreateButton() { const [creationStatus, setCreationStatus] = useState(null); const [createdCarpoolId, setCreatedCarpoolId] = useState(null); - const me = useMe()!; + const me = useMe() || { id: 0, name: '' }; const myCarpool = useMyCarpool(); const createCarpoolCallback = useCallback(async () => { diff --git a/src/components/Event/EventHooks.ts b/src/components/Event/EventHooks.ts index 1e43a38..1875960 100644 --- a/src/components/Event/EventHooks.ts +++ b/src/components/Event/EventHooks.ts @@ -12,7 +12,7 @@ export function useSignups() { export function useMySignup() { const signups = useSignups(); - const me = useMe()!; + const me = useMe() || { id: 0, name: '' }; const signup = useMemo(() => signups[me.id] ?? null, [signups, me.id]); @@ -22,7 +22,7 @@ export function useMySignup() { } export function useMyCarpool() { - const me = useMe()!; + const me = useMe() || { id: 0, name: '' }; const { event } = useContext(EventContext); const carpool = useMemo( diff --git a/src/components/Event/EventPage.tsx b/src/components/Event/EventPage.tsx index 42a4e04..c18acee 100644 --- a/src/components/Event/EventPage.tsx +++ b/src/components/Event/EventPage.tsx @@ -1,22 +1,14 @@ -import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { getEvent } from '../api'; import Header from '../Header/Header'; -import { IEvent } from '../types'; import Event from './Event'; export default function EventPage() { const id = +useParams<{ id: string }>().id; - const [event, setEvent] = useState(null); - - useEffect(() => { - getEvent(id).then(setEvent); - }, [id]); return ( <>
- {event ? : Loading...} + ); } diff --git a/src/components/GroupJoinerLink.tsx b/src/components/GroupJoinerLink.tsx index c122e38..139edc1 100644 --- a/src/components/GroupJoinerLink.tsx +++ b/src/components/GroupJoinerLink.tsx @@ -51,7 +51,9 @@ function GroupJoiner() { {group && ( <>
- Found group: {group.name} + + Found group: {group.name} + ([]); - // eslint-disable-next-line + useEffect(() => { getGroups().then(setGroups); }, []); diff --git a/src/components/UseImmutableTest.tsx b/src/components/UseImmutableTest.tsx index 37ac47c..9cf3425 100644 --- a/src/components/UseImmutableTest.tsx +++ b/src/components/UseImmutableTest.tsx @@ -10,7 +10,7 @@ export default function UseImmutableTest() { return (
{JSON.stringify(imm)} - Reset button +
diff --git a/src/state/EventsProvider.tsx b/src/state/EventsProvider.tsx deleted file mode 100644 index d02c132..0000000 --- a/src/state/EventsProvider.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { createContext, ReactNode, useCallback, useState } from 'react'; -import * as immutable from 'immutable'; -import { useMemo } from 'react'; - -export class EventSignup extends immutable.Record({ - userId: 0, - placeId: '', - formattedAddress: '', - latitute: 0, - longitude: 0, -}) {} - -export class EventState extends immutable.Record({ - id: 0, - name: '', - signups: immutable.Map(), -}) { - addSignup( - userId: number, - placeId: string, - formattedAddress: string, - latitute: number, - longitude: number - ) { - return this.set( - 'signups', - this.signups.set( - userId.toString(), - new EventSignup({ - userId, - placeId, - formattedAddress, - latitute, - longitude, - }) - ) - ); - } - setName(name: string) { - return this.set('name', name); - } -} - -type EventsProps = { - events: immutable.Map; - upsertEvent: (event: EventState) => void; -}; - -export const EventsContext = createContext({ - events: immutable.Map(), - upsertEvent: () => {}, -}); - -export default function EventsProvider({ children }: { children: ReactNode }) { - const [events, setEvents] = useState(immutable.Map()); - - const upsertEvent = useCallback( - (event: EventState) => { - setEvents(events.set(event.id, event)); - }, - [events] - ); - - const value: EventsProps = useMemo(() => { - return { - events, - upsertEvent, - }; - }, [events, upsertEvent]); - - return ( - {children} - ); -} diff --git a/src/state/GroupHooks.tsx b/src/state/GroupHooks.tsx deleted file mode 100644 index 5a438d8..0000000 --- a/src/state/GroupHooks.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { useContext } from 'react'; -import { GroupsContext, GroupState } from './GroupsProvider'; - -export function useGroup(id: number): GroupState | null { - const { groups } = useContext(GroupsContext); - return groups.get(id, null); -} diff --git a/src/state/GroupsProvider.tsx b/src/state/GroupsProvider.tsx deleted file mode 100644 index 74cde72..0000000 --- a/src/state/GroupsProvider.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import * as immutable from 'immutable'; -import { ReactNode, useCallback, useMemo, useState } from 'react'; -import { createContext } from 'react'; -import { getGroup as fetchGroup } from '../components/api'; - -export class GroupState extends immutable.Record({ - id: 0, - name: '', - memberIds: immutable.Set(), - joinCode: null as string | null, -}) { - setJoinCode(joinCode: string) { - return this.set('joinCode', joinCode); - } - setName(name: string) { - return this.set('name', name); - } - addMember(memberId: number) { - return this.set('memberIds', this.memberIds.add(memberId)); - } - removeMember(memberId: number) { - return this.set('memberIds', this.memberIds.remove(memberId)); - } - setMemberIds(memberIds: immutable.Set) { - return this.set('memberIds', memberIds); - } -} - -function u(name: string) { - return () => { - throw new Error(`${name} is not implemented`); - }; -} - -type GroupContextProps = { - groups: immutable.Map; - addGroup: (group: GroupState) => void; - getGroup: (id: number) => Promise; - renameGroup: (groupId: number, name: string) => void; - generateJoinCode: (groupId: number) => void; -}; - -// A React context that provides access to the current user's groups. -export const GroupsContext = createContext({ - groups: immutable.Map(), - addGroup: u('addGroup'), - getGroup: u('getGroup'), - renameGroup: u('renameGroup'), - generateJoinCode: u('generateJoinCode'), -}); - -export default function GroupsProvider({ children }: { children: ReactNode }) { - // usestates for all the properties in GroupsContext - const [groups, setGroups] = useState(immutable.Map()); - - const addGroup = useCallback((group: GroupState) => { - setGroups((groups) => groups.set(group.id, group)); - }, []); - - const renameGroup = useCallback((groupId: number, name: string) => { - setGroups((groups) => groups.setIn([groupId, 'name'], name)); - }, []); - - const generateJoinCode = useCallback((groupId: number) => { - // TODO actually use the API here, this was generated by copilot - setGroups((groups) => - groups.setIn( - [groupId, 'joinCode'], - Math.random().toString(36).substr(2, 5) - ) - ); - }, []); - - const getGroup = useCallback( - async (id: number) => { - const group = groups.get(id); - if (group) { - return group; - } else { - const group = await fetchGroup(id); - const state = new GroupState({ - id: group.id, - name: group.name, - }); - addGroup(state); - return state; - } - }, - [addGroup, groups] - ); - - const value: GroupContextProps = useMemo(() => { - return { - groups, - addGroup, - getGroup, - renameGroup, - generateJoinCode, - }; - }, [addGroup, generateJoinCode, getGroup, groups, renameGroup]); - - return ( - {children} - ); -} diff --git a/src/state/Notifications/NotificationsHooks.tsx b/src/state/Notifications/NotificationsHooks.tsx index dbb3f70..0758527 100644 --- a/src/state/Notifications/NotificationsHooks.tsx +++ b/src/state/Notifications/NotificationsHooks.tsx @@ -13,16 +13,17 @@ export function useCancelCarpoolRequest() { export function useInvitationState( carpoolId: number ): 'invited' | 'requested' | 'none' { - const notifications = useContext(NotificationsContext); + const { invitedCarpoolIds, requestedCarpoolIds } = + useContext(NotificationsContext); const invited = useMemo( - () => notifications.invitedCarpoolIds.has(carpoolId), - [carpoolId, notifications.invitedCarpoolIds] + () => carpoolId in invitedCarpoolIds, + [carpoolId, invitedCarpoolIds] ); const requested = useMemo( - () => notifications.requestedCarpoolIds.has(carpoolId), - [carpoolId, notifications.requestedCarpoolIds] + () => carpoolId in requestedCarpoolIds, + [carpoolId, requestedCarpoolIds] ); return invited ? 'invited' : requested ? 'requested' : 'none'; diff --git a/src/state/Notifications/NotificationsProvider.tsx b/src/state/Notifications/NotificationsProvider.tsx index 8c7e069..4556f09 100644 --- a/src/state/Notifications/NotificationsProvider.tsx +++ b/src/state/Notifications/NotificationsProvider.tsx @@ -1,11 +1,11 @@ -import { createContext, ReactNode, useCallback, useState } from 'react'; -import * as immutable from 'immutable'; +import { createContext, ReactNode, useCallback } from 'react'; import * as api from '../../components/api'; import { useEffect } from 'react'; +import useImmutable from '../../components/useImmutable'; export const NotificationsContext = createContext({ - invitedCarpoolIds: immutable.Set(), - requestedCarpoolIds: immutable.Set(), + invitedCarpoolIds: {} as Record, + requestedCarpoolIds: {} as Record, sendCarpoolRequest: (carpoolId: number) => console.error('not implemented: sendCarpoolRequest'), @@ -19,44 +19,47 @@ export default function NotificationsProvider({ }: { children: ReactNode; }) { - const [invitedCarpoolIds, setInvitedCarpoolIds] = useState( - immutable.Set() - ); - - const [requestedCarpoolIds, setRequestedCarpoolIds] = useState( - immutable.Set() - ); + const [invitedCarpoolIds, setInvitedCarpoolIds] = useImmutable< + Record + >({}); + const [requestedCarpoolIds, setRequestedCarpoolIds] = useImmutable< + Record + >({}); useEffect(() => { api.getSentRequestsAndInvites().then((invitations) => { - setInvitedCarpoolIds((ids) => - ids.concat( - invitations - .filter((invite) => !invite.isRequest) - .map((invite) => invite.carpool.id) - ) - ); - setRequestedCarpoolIds((ids) => - ids.concat( - invitations - .filter((invite) => invite.isRequest) - .map((invite) => invite.carpool.id) - ) - ); + const invited = {} as Record; + const requested = {} as Record; + for (let invitation of invitations) { + if (invitation.isRequest) { + invited[invitation.carpool.id] = true; + } else { + requested[invitation.carpool.id] = true; + } + } + + setInvitedCarpoolIds(invited); + setRequestedCarpoolIds(requested); }); - }, []); + }, [setInvitedCarpoolIds, setRequestedCarpoolIds]); - const sendCarpoolRequest = useCallback((carpoolId: number) => { - api - .sendCarpoolRequest(carpoolId) - .then(() => setRequestedCarpoolIds((ids) => ids.add(carpoolId))); - }, []); + const sendCarpoolRequest = useCallback( + (carpoolId: number) => { + api.sendCarpoolRequest(carpoolId).then(() => { + requestedCarpoolIds[carpoolId] = true; + }); + }, + [requestedCarpoolIds] + ); - const cancelCarpoolRequest = useCallback((carpoolId: number) => { - api - .cancelCarpoolRequest(carpoolId) - .then(() => setRequestedCarpoolIds((ids) => ids.delete(carpoolId))); - }, []); + const cancelCarpoolRequest = useCallback( + (carpoolId: number) => { + api.cancelCarpoolRequest(carpoolId).then(() => { + delete requestedCarpoolIds[carpoolId]; + }); + }, + [requestedCarpoolIds] + ); return (