mirror of
https://github.com/myfatemi04/wheelshare-frontend.git
synced 2025-04-21 11:20:17 -04:00
add grouphooks, groupprovider (probably will not be used)
This commit is contained in:
parent
efeaf4b3d6
commit
bafc26fb06
|
@ -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,28 +25,30 @@ export default function App() {
|
||||||
const user = useMe();
|
const user = useMe();
|
||||||
return (
|
return (
|
||||||
<NotificationsProvider>
|
<NotificationsProvider>
|
||||||
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
<GroupsProvider>
|
||||||
<div style={style}>
|
<div style={{ padding: '1rem', maxWidth: '100vw' }}>
|
||||||
<BrowserRouter>
|
<div style={style}>
|
||||||
<Switch>
|
<BrowserRouter>
|
||||||
<Route
|
<Switch>
|
||||||
path="/"
|
|
||||||
exact
|
|
||||||
component={user ? WheelShare : WheelShareLoggedOut}
|
|
||||||
/>
|
|
||||||
<Suspense fallback={null}>
|
|
||||||
<Route path="/groups/:id" component={Group} />
|
|
||||||
<Route
|
<Route
|
||||||
component={Authenticator}
|
path="/"
|
||||||
path="/auth/:provider/callback"
|
exact
|
||||||
|
component={user ? WheelShare : WheelShareLoggedOut}
|
||||||
/>
|
/>
|
||||||
<Route path="/carpools/:id" component={CarpoolPage} />
|
<Suspense fallback={null}>
|
||||||
<Route path="/events/:id" component={EventPage} />
|
<Route path="/groups/:id" component={Group} />
|
||||||
</Suspense>
|
<Route
|
||||||
</Switch>
|
component={Authenticator}
|
||||||
</BrowserRouter>
|
path="/auth/:provider/callback"
|
||||||
|
/>
|
||||||
|
<Route path="/carpools/:id" component={CarpoolPage} />
|
||||||
|
<Route path="/events/:id" component={EventPage} />
|
||||||
|
</Suspense>
|
||||||
|
</Switch>
|
||||||
|
</BrowserRouter>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</GroupsProvider>
|
||||||
</NotificationsProvider>
|
</NotificationsProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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 }) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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 }) {
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ export type ICarpool = {
|
||||||
export type IGroup = {
|
export type IGroup = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
events: IEvent[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
74
src/state/EventsProvider.tsx
Normal file
74
src/state/EventsProvider.tsx
Normal 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
7
src/state/GroupHooks.tsx
Normal 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);
|
||||||
|
}
|
105
src/state/GroupsProvider.tsx
Normal file
105
src/state/GroupsProvider.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user