mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-21 11:20:17 -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 { CSSProperties, lazy, Suspense } from 'react';
|
||||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||||
import GroupsProvider from '../state/GroupsProvider';
|
|
||||||
import NotificationsProvider from '../state/Notifications/NotificationsProvider';
|
import NotificationsProvider from '../state/Notifications/NotificationsProvider';
|
||||||
import { useMe } from './hooks';
|
import { useMe } from './hooks';
|
||||||
|
import UseImmutableTest from './UseImmutableTest';
|
||||||
import WheelShare from './WheelShare';
|
import WheelShare from './WheelShare';
|
||||||
import WheelShareLoggedOut from './WheelShareLoggedOut';
|
import WheelShareLoggedOut from './WheelShareLoggedOut';
|
||||||
|
|
||||||
|
@ -26,30 +26,29 @@ export default function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NotificationsProvider>
|
<NotificationsProvider>
|
||||||
<GroupsProvider>
|
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
||||||
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
<UseImmutableTest />
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
<Route
|
||||||
|
path="/"
|
||||||
|
exact
|
||||||
|
component={user ? WheelShare : WheelShareLoggedOut}
|
||||||
|
/>
|
||||||
|
<Suspense fallback={null}>
|
||||||
<Route
|
<Route
|
||||||
path="/"
|
component={Authenticator}
|
||||||
exact
|
path="/auth/:provider/callback"
|
||||||
component={user ? WheelShare : WheelShareLoggedOut}
|
|
||||||
/>
|
/>
|
||||||
<Suspense fallback={null}>
|
<Route path="/carpools/:id" component={CarpoolPage} />
|
||||||
<Route
|
<Route path="/events/:id" component={EventPage} />
|
||||||
component={Authenticator}
|
<Route path="/groups/:id" component={Group} />
|
||||||
path="/auth/:provider/callback"
|
</Suspense>
|
||||||
/>
|
</Switch>
|
||||||
<Route path="/carpools/:id" component={CarpoolPage} />
|
</BrowserRouter>
|
||||||
<Route path="/events/:id" component={EventPage} />
|
|
||||||
<Route path="/groups/:id" component={Group} />
|
|
||||||
</Suspense>
|
|
||||||
</Switch>
|
|
||||||
</BrowserRouter>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</GroupsProvider>
|
</div>
|
||||||
</NotificationsProvider>
|
</NotificationsProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default function MemberList() {
|
||||||
cancelCarpoolRequest(carpool.id);
|
cancelCarpoolRequest(carpool.id);
|
||||||
}, [carpool.id, cancelCarpoolRequest]);
|
}, [carpool.id, cancelCarpoolRequest]);
|
||||||
|
|
||||||
const me = useMe()!;
|
const me = useMe() || { id: 0, name: '' };
|
||||||
|
|
||||||
const isMember = useMemo(() => {
|
const isMember = useMemo(() => {
|
||||||
return members.some(({ id }) => id === me?.id);
|
return members.some(({ id }) => id === me?.id);
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default function Event({
|
||||||
...(initial || {}),
|
...(initial || {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const me = useMe()!;
|
const me = useMe() || { id: 0, name: '' };
|
||||||
|
|
||||||
const [tentativeInvites] = useImmutable<Record<number, boolean>>({});
|
const [tentativeInvites] = useImmutable<Record<number, boolean>>({});
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default function EventCarpoolCreateButton() {
|
||||||
const [creationStatus, setCreationStatus] = useState<CreationStatus>(null);
|
const [creationStatus, setCreationStatus] = useState<CreationStatus>(null);
|
||||||
const [createdCarpoolId, setCreatedCarpoolId] = useState<null | number>(null);
|
const [createdCarpoolId, setCreatedCarpoolId] = useState<null | number>(null);
|
||||||
|
|
||||||
const me = useMe()!;
|
const me = useMe() || { id: 0, name: '' };
|
||||||
const myCarpool = useMyCarpool();
|
const myCarpool = useMyCarpool();
|
||||||
|
|
||||||
const createCarpoolCallback = useCallback(async () => {
|
const createCarpoolCallback = useCallback(async () => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ export function useSignups() {
|
||||||
|
|
||||||
export function useMySignup() {
|
export function useMySignup() {
|
||||||
const signups = useSignups();
|
const signups = useSignups();
|
||||||
const me = useMe()!;
|
const me = useMe() || { id: 0, name: '' };
|
||||||
|
|
||||||
const signup = useMemo(() => signups[me.id] ?? null, [signups, me.id]);
|
const signup = useMemo(() => signups[me.id] ?? null, [signups, me.id]);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ export function useMySignup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMyCarpool() {
|
export function useMyCarpool() {
|
||||||
const me = useMe()!;
|
const me = useMe() || { id: 0, name: '' };
|
||||||
const { event } = useContext(EventContext);
|
const { event } = useContext(EventContext);
|
||||||
|
|
||||||
const carpool = useMemo(
|
const carpool = useMemo(
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { getEvent } from '../api';
|
|
||||||
import Header from '../Header/Header';
|
import Header from '../Header/Header';
|
||||||
import { IEvent } from '../types';
|
|
||||||
import Event from './Event';
|
import Event from './Event';
|
||||||
|
|
||||||
export default function EventPage() {
|
export default function EventPage() {
|
||||||
const id = +useParams<{ id: string }>().id;
|
const id = +useParams<{ id: string }>().id;
|
||||||
const [event, setEvent] = useState<IEvent | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getEvent(id).then(setEvent);
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header />
|
||||||
{event ? <Event id={id} /> : <span>Loading...</span>}
|
<Event id={id} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,9 @@ function GroupJoiner() {
|
||||||
{group && (
|
{group && (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
<span>Found group: {group.name}</span>
|
<span>
|
||||||
|
Found group: <b>{group.name}</b>
|
||||||
|
</span>
|
||||||
<UIButton
|
<UIButton
|
||||||
onClick={join}
|
onClick={join}
|
||||||
style={!buttonEnabled ? { color: 'grey' } : {}}
|
style={!buttonEnabled ? { color: 'grey' } : {}}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import GroupList from './GroupList';
|
||||||
|
|
||||||
export default function Groups() {
|
export default function Groups() {
|
||||||
const [groups, setGroups] = useState<IGroup[]>([]);
|
const [groups, setGroups] = useState<IGroup[]>([]);
|
||||||
// eslint-disable-next-line
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getGroups().then(setGroups);
|
getGroups().then(setGroups);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default function UseImmutableTest() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{JSON.stringify(imm)}
|
{JSON.stringify(imm)}
|
||||||
Reset button
|
<br />
|
||||||
<button onClick={() => imm.z.a++}>Increment</button>
|
<button onClick={() => imm.z.a++}>Increment</button>
|
||||||
<button onClick={() => imm.z.c.push(imm.z.c.length)}>Push</button>
|
<button onClick={() => imm.z.c.push(imm.z.c.length)}>Push</button>
|
||||||
</div>
|
</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(
|
export function useInvitationState(
|
||||||
carpoolId: number
|
carpoolId: number
|
||||||
): 'invited' | 'requested' | 'none' {
|
): 'invited' | 'requested' | 'none' {
|
||||||
const notifications = useContext(NotificationsContext);
|
const { invitedCarpoolIds, requestedCarpoolIds } =
|
||||||
|
useContext(NotificationsContext);
|
||||||
|
|
||||||
const invited = useMemo(
|
const invited = useMemo(
|
||||||
() => notifications.invitedCarpoolIds.has(carpoolId),
|
() => carpoolId in invitedCarpoolIds,
|
||||||
[carpoolId, notifications.invitedCarpoolIds]
|
[carpoolId, invitedCarpoolIds]
|
||||||
);
|
);
|
||||||
|
|
||||||
const requested = useMemo(
|
const requested = useMemo(
|
||||||
() => notifications.requestedCarpoolIds.has(carpoolId),
|
() => carpoolId in requestedCarpoolIds,
|
||||||
[carpoolId, notifications.requestedCarpoolIds]
|
[carpoolId, requestedCarpoolIds]
|
||||||
);
|
);
|
||||||
|
|
||||||
return invited ? 'invited' : requested ? 'requested' : 'none';
|
return invited ? 'invited' : requested ? 'requested' : 'none';
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { createContext, ReactNode, useCallback, useState } from 'react';
|
import { createContext, ReactNode, useCallback } from 'react';
|
||||||
import * as immutable from 'immutable';
|
|
||||||
import * as api from '../../components/api';
|
import * as api from '../../components/api';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import useImmutable from '../../components/useImmutable';
|
||||||
|
|
||||||
export const NotificationsContext = createContext({
|
export const NotificationsContext = createContext({
|
||||||
invitedCarpoolIds: immutable.Set<number>(),
|
invitedCarpoolIds: {} as Record<number, boolean>,
|
||||||
requestedCarpoolIds: immutable.Set<number>(),
|
requestedCarpoolIds: {} as Record<number, boolean>,
|
||||||
|
|
||||||
sendCarpoolRequest: (carpoolId: number) =>
|
sendCarpoolRequest: (carpoolId: number) =>
|
||||||
console.error('not implemented: sendCarpoolRequest'),
|
console.error('not implemented: sendCarpoolRequest'),
|
||||||
|
@ -19,44 +19,47 @@ export default function NotificationsProvider({
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const [invitedCarpoolIds, setInvitedCarpoolIds] = useState(
|
const [invitedCarpoolIds, setInvitedCarpoolIds] = useImmutable<
|
||||||
immutable.Set<number>()
|
Record<number, boolean>
|
||||||
);
|
>({});
|
||||||
|
const [requestedCarpoolIds, setRequestedCarpoolIds] = useImmutable<
|
||||||
const [requestedCarpoolIds, setRequestedCarpoolIds] = useState(
|
Record<number, boolean>
|
||||||
immutable.Set<number>()
|
>({});
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.getSentRequestsAndInvites().then((invitations) => {
|
api.getSentRequestsAndInvites().then((invitations) => {
|
||||||
setInvitedCarpoolIds((ids) =>
|
const invited = {} as Record<number, boolean>;
|
||||||
ids.concat(
|
const requested = {} as Record<number, boolean>;
|
||||||
invitations
|
for (let invitation of invitations) {
|
||||||
.filter((invite) => !invite.isRequest)
|
if (invitation.isRequest) {
|
||||||
.map((invite) => invite.carpool.id)
|
invited[invitation.carpool.id] = true;
|
||||||
)
|
} else {
|
||||||
);
|
requested[invitation.carpool.id] = true;
|
||||||
setRequestedCarpoolIds((ids) =>
|
}
|
||||||
ids.concat(
|
}
|
||||||
invitations
|
|
||||||
.filter((invite) => invite.isRequest)
|
setInvitedCarpoolIds(invited);
|
||||||
.map((invite) => invite.carpool.id)
|
setRequestedCarpoolIds(requested);
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}, []);
|
}, [setInvitedCarpoolIds, setRequestedCarpoolIds]);
|
||||||
|
|
||||||
const sendCarpoolRequest = useCallback((carpoolId: number) => {
|
const sendCarpoolRequest = useCallback(
|
||||||
api
|
(carpoolId: number) => {
|
||||||
.sendCarpoolRequest(carpoolId)
|
api.sendCarpoolRequest(carpoolId).then(() => {
|
||||||
.then(() => setRequestedCarpoolIds((ids) => ids.add(carpoolId)));
|
requestedCarpoolIds[carpoolId] = true;
|
||||||
}, []);
|
});
|
||||||
|
},
|
||||||
|
[requestedCarpoolIds]
|
||||||
|
);
|
||||||
|
|
||||||
const cancelCarpoolRequest = useCallback((carpoolId: number) => {
|
const cancelCarpoolRequest = useCallback(
|
||||||
api
|
(carpoolId: number) => {
|
||||||
.cancelCarpoolRequest(carpoolId)
|
api.cancelCarpoolRequest(carpoolId).then(() => {
|
||||||
.then(() => setRequestedCarpoolIds((ids) => ids.delete(carpoolId)));
|
delete requestedCarpoolIds[carpoolId];
|
||||||
}, []);
|
});
|
||||||
|
},
|
||||||
|
[requestedCarpoolIds]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NotificationsContext.Provider
|
<NotificationsContext.Provider
|
||||||
|
|
Loading…
Reference in New Issue
Block a user