add grouphooks, groupprovider (probably will not be used)

This commit is contained in:
Michael Fatemi 2021-07-13 20:48:10 -04:00
parent efeaf4b3d6
commit bafc26fb06
12 changed files with 218 additions and 34 deletions

View File

@ -1,5 +1,6 @@
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 WheelShare from './WheelShare'; import WheelShare from './WheelShare';
@ -24,6 +25,7 @@ export default function App() {
const user = useMe(); const user = useMe();
return ( return (
<NotificationsProvider> <NotificationsProvider>
<GroupsProvider>
<div style={{ padding: '1rem', maxWidth: '100vw' }}> <div style={{ padding: '1rem', maxWidth: '100vw' }}>
<div style={style}> <div style={style}>
<BrowserRouter> <BrowserRouter>
@ -46,6 +48,7 @@ export default function App() {
</BrowserRouter> </BrowserRouter>
</div> </div>
</div> </div>
</GroupsProvider>
</NotificationsProvider> </NotificationsProvider>
); );
} }

View File

@ -1,7 +1,7 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { createEvent } from '../api';
import { green, lightgrey } from '../../lib/colors'; import { green, lightgrey } from '../../lib/colors';
import { IGroup } from '../Group'; import { createEvent } from '../api';
import { IGroup } from '../types';
import UIButton from '../UI/UIButton'; import UIButton from '../UI/UIButton';
import UIDateInput from '../UI/UIDateInput'; import UIDateInput from '../UI/UIDateInput';
import UIDatetimeInput from '../UI/UIDatetimeInput'; import UIDatetimeInput from '../UI/UIDatetimeInput';

View File

@ -1,5 +1,5 @@
import EventCreator from './EventCreator'; import EventCreator from './EventCreator';
import { IGroup } from '../Group'; import { IGroup } from '../types';
import useToggle from '../useToggle'; import useToggle from '../useToggle';
export default function EventCreatorLink({ group }: { group: IGroup }) { export default function EventCreatorLink({ group }: { group: IGroup }) {

View File

@ -5,15 +5,9 @@ import { getGroup, getGroupEvents } from './api';
import EventCreatorLink from './EventCreator/EventCreatorLink'; import EventCreatorLink from './EventCreator/EventCreatorLink';
import EventStream from './EventStream'; import EventStream from './EventStream';
import GroupSettingsLink from './GroupSettings/GroupSettingsLink'; import GroupSettingsLink from './GroupSettings/GroupSettingsLink';
import { IEvent } from './types'; import { IEvent, IGroup } from './types';
import UILink from './UI/UILink'; import UILink from './UI/UILink';
export type IGroup = {
id: number;
events: IEvent[];
name: string;
};
export default function Group() { export default function Group() {
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);

View File

@ -1,4 +1,4 @@
import { IGroup } from '../Group'; import { IGroup } from '../types';
import useToggle from '../useToggle'; import useToggle from '../useToggle';
import GroupSettings from './GroupSettings'; import GroupSettings from './GroupSettings';

View File

@ -1,4 +1,4 @@
import { IGroup } from '../Group'; import { IGroup } from '../types';
import UISecondaryBox from '../UI/UISecondaryBox'; import UISecondaryBox from '../UI/UISecondaryBox';
function GroupListItem({ group }: { group: IGroup }) { function GroupListItem({ group }: { group: IGroup }) {

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { getGroups } from '../api'; import { getGroups } from '../api';
import { IGroup } from '../Group'; import { IGroup } from '../types';
import GroupCreatorLink from '../GroupCreator/GroupCreatorLink'; import GroupCreatorLink from '../GroupCreator/GroupCreatorLink';
import GroupJoinerLink from '../GroupJoinerLink'; import GroupJoinerLink from '../GroupJoinerLink';
import GroupList from './GroupList'; import GroupList from './GroupList';

View File

@ -1,5 +1,5 @@
import { GroupPreview } from './GroupJoinerLink'; import { GroupPreview } from './GroupJoinerLink';
import { IInvitation, IEventSignup, ICarpool, IEvent } from './types'; import { IInvitation, IEventSignup, ICarpool, IEvent, IGroup } from './types';
const base = process.env.REACT_APP_API_DOMAIN + 'api'; const base = process.env.REACT_APP_API_DOMAIN + 'api';
@ -94,7 +94,7 @@ export async function getEvent(id: number): Promise<IEvent> {
return await get('/events/' + id); return await get('/events/' + id);
} }
export async function getGroup(id: number) { export async function getGroup(id: number): Promise<IGroup> {
return await get('/groups/' + id); return await get('/groups/' + id);
} }

View File

@ -49,6 +49,7 @@ export type ICarpool = {
export type IGroup = { export type IGroup = {
id: number; id: number;
name: string; name: string;
events: IEvent[];
}; };
/** /**

View File

@ -0,0 +1,74 @@
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>
);
}

7
src/state/GroupHooks.tsx Normal file
View File

@ -0,0 +1,7 @@
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);
}

View File

@ -0,0 +1,105 @@
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>
);
}