mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-16 00:50:18 -04:00
remove more usestates
This commit is contained in:
parent
9bf4f4c568
commit
9f7c40c7df
|
@ -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 (
|
||||
<NotificationsProvider>
|
||||
<GroupsProvider>
|
||||
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
||||
<div style={style}>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
||||
<UseImmutableTest />
|
||||
<div style={style}>
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/"
|
||||
exact
|
||||
component={user ? WheelShare : WheelShareLoggedOut}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<Route
|
||||
path="/"
|
||||
exact
|
||||
component={user ? WheelShare : WheelShareLoggedOut}
|
||||
component={Authenticator}
|
||||
path="/auth/:provider/callback"
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<Route
|
||||
component={Authenticator}
|
||||
path="/auth/:provider/callback"
|
||||
/>
|
||||
<Route path="/carpools/:id" component={CarpoolPage} />
|
||||
<Route path="/events/:id" component={EventPage} />
|
||||
<Route path="/groups/:id" component={Group} />
|
||||
</Suspense>
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
<Route path="/carpools/:id" component={CarpoolPage} />
|
||||
<Route path="/events/:id" component={EventPage} />
|
||||
<Route path="/groups/:id" component={Group} />
|
||||
</Suspense>
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
</GroupsProvider>
|
||||
</div>
|
||||
</NotificationsProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -46,7 +46,7 @@ export default function Event({
|
|||
...(initial || {}),
|
||||
});
|
||||
|
||||
const me = useMe()!;
|
||||
const me = useMe() || { id: 0, name: '' };
|
||||
|
||||
const [tentativeInvites] = useImmutable<Record<number, boolean>>({});
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function EventCarpoolCreateButton() {
|
|||
const [creationStatus, setCreationStatus] = useState<CreationStatus>(null);
|
||||
const [createdCarpoolId, setCreatedCarpoolId] = useState<null | number>(null);
|
||||
|
||||
const me = useMe()!;
|
||||
const me = useMe() || { id: 0, name: '' };
|
||||
const myCarpool = useMyCarpool();
|
||||
|
||||
const createCarpoolCallback = useCallback(async () => {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<IEvent | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
getEvent(id).then(setEvent);
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
{event ? <Event id={id} /> : <span>Loading...</span>}
|
||||
<Event id={id} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,9 @@ function GroupJoiner() {
|
|||
{group && (
|
||||
<>
|
||||
<br />
|
||||
<span>Found group: {group.name}</span>
|
||||
<span>
|
||||
Found group: <b>{group.name}</b>
|
||||
</span>
|
||||
<UIButton
|
||||
onClick={join}
|
||||
style={!buttonEnabled ? { color: 'grey' } : {}}
|
||||
|
|
|
@ -7,7 +7,7 @@ import GroupList from './GroupList';
|
|||
|
||||
export default function Groups() {
|
||||
const [groups, setGroups] = useState<IGroup[]>([]);
|
||||
// eslint-disable-next-line
|
||||
|
||||
useEffect(() => {
|
||||
getGroups().then(setGroups);
|
||||
}, []);
|
||||
|
|
|
@ -10,7 +10,7 @@ export default function UseImmutableTest() {
|
|||
return (
|
||||
<div>
|
||||
{JSON.stringify(imm)}
|
||||
Reset button
|
||||
<br />
|
||||
<button onClick={() => imm.z.a++}>Increment</button>
|
||||
<button onClick={() => imm.z.c.push(imm.z.c.length)}>Push</button>
|
||||
</div>
|
||||
|
|
|
@ -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<string, EventSignup>(),
|
||||
}) {
|
||||
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<number, EventState>;
|
||||
upsertEvent: (event: EventState) => void;
|
||||
};
|
||||
|
||||
export const EventsContext = createContext<EventsProps>({
|
||||
events: immutable.Map<number, EventState>(),
|
||||
upsertEvent: () => {},
|
||||
});
|
||||
|
||||
export default function EventsProvider({ children }: { children: ReactNode }) {
|
||||
const [events, setEvents] = useState(immutable.Map<number, EventState>());
|
||||
|
||||
const upsertEvent = useCallback(
|
||||
(event: EventState) => {
|
||||
setEvents(events.set(event.id, event));
|
||||
},
|
||||
[events]
|
||||
);
|
||||
|
||||
const value: EventsProps = useMemo(() => {
|
||||
return {
|
||||
events,
|
||||
upsertEvent,
|
||||
};
|
||||
}, [events, upsertEvent]);
|
||||
|
||||
return (
|
||||
<EventsContext.Provider value={value}>{children}</EventsContext.Provider>
|
||||
);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<number>(),
|
||||
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<number>) {
|
||||
return this.set('memberIds', memberIds);
|
||||
}
|
||||
}
|
||||
|
||||
function u(name: string) {
|
||||
return () => {
|
||||
throw new Error(`${name} is not implemented`);
|
||||
};
|
||||
}
|
||||
|
||||
type GroupContextProps = {
|
||||
groups: immutable.Map<number, GroupState>;
|
||||
addGroup: (group: GroupState) => void;
|
||||
getGroup: (id: number) => Promise<GroupState | null>;
|
||||
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<GroupContextProps>({
|
||||
groups: immutable.Map<number, GroupState>(),
|
||||
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<number, GroupState>());
|
||||
|
||||
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 (
|
||||
<GroupsContext.Provider value={value}>{children}</GroupsContext.Provider>
|
||||
);
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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<number>(),
|
||||
requestedCarpoolIds: immutable.Set<number>(),
|
||||
invitedCarpoolIds: {} as Record<number, boolean>,
|
||||
requestedCarpoolIds: {} as Record<number, boolean>,
|
||||
|
||||
sendCarpoolRequest: (carpoolId: number) =>
|
||||
console.error('not implemented: sendCarpoolRequest'),
|
||||
|
@ -19,44 +19,47 @@ export default function NotificationsProvider({
|
|||
}: {
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const [invitedCarpoolIds, setInvitedCarpoolIds] = useState(
|
||||
immutable.Set<number>()
|
||||
);
|
||||
|
||||
const [requestedCarpoolIds, setRequestedCarpoolIds] = useState(
|
||||
immutable.Set<number>()
|
||||
);
|
||||
const [invitedCarpoolIds, setInvitedCarpoolIds] = useImmutable<
|
||||
Record<number, boolean>
|
||||
>({});
|
||||
const [requestedCarpoolIds, setRequestedCarpoolIds] = useImmutable<
|
||||
Record<number, boolean>
|
||||
>({});
|
||||
|
||||
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<number, boolean>;
|
||||
const requested = {} as Record<number, boolean>;
|
||||
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 (
|
||||
<NotificationsContext.Provider
|
||||
|
|
Loading…
Reference in New Issue
Block a user