Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

My home #2425

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft

My home #2425

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ export default async function Page({ params }: PageProps) {

return <MyCanvassAssignmentPage canvassAssId={canvassAssId} />;
} catch (err) {
return redirect(`/login?redirect=/my/canvassassignments/${canvassAssId}`);
return redirect(`/login?redirect=/canvass/${canvassAssId}`);
}
}
21 changes: 0 additions & 21 deletions src/app/my/canvassassignments/page.tsx

This file was deleted.

5 changes: 5 additions & 0 deletions src/app/my/feed/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AllEventsPage from 'features/home/pages/AllEventsPage';

export default async function Page() {
return <AllEventsPage />;
}
5 changes: 5 additions & 0 deletions src/app/my/home/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import HomePage from 'features/home/pages/HomePage';

export default async function Page() {
return <HomePage />;
}
13 changes: 13 additions & 0 deletions src/app/my/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FC, ReactNode } from 'react';

import HomeLayout from 'features/home/layouts/HomeLayout';

type Props = {
children: ReactNode;
};

const MyHomeLayout: FC<Props> = ({ children }) => {
return <HomeLayout>{children}</HomeLayout>;
};

export default MyHomeLayout;
6 changes: 3 additions & 3 deletions src/core/Providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { EventPopperProvider } from 'features/events/components/EventPopper/Even
import { MessageList } from 'utils/locale';
import { Store } from './store';
import { themeWithLocale } from '../theme';
import { UserContext } from 'utils/hooks/useFocusDate';
import { ZetkinUser } from 'utils/types/zetkin';
import { ZUIConfirmDialogProvider } from 'zui/ZUIConfirmDialogProvider';
import { ZUISnackbarProvider } from 'zui/ZUISnackbarContext';
import { UserProvider } from './env/UserContext';

type ProviderData = {
env: Environment;
Expand Down Expand Up @@ -63,7 +63,7 @@ const Providers: FC<ProvidersProps> = ({
return (
<ReduxProvider store={store}>
<EnvProvider env={env}>
<UserContext.Provider value={user}>
<UserProvider user={user}>
<StyledEngineProvider injectFirst>
<CacheProvider value={cache}>
<ThemeProvider theme={themeWithLocale(lang)}>
Expand All @@ -87,7 +87,7 @@ const Providers: FC<ProvidersProps> = ({
</ThemeProvider>
</CacheProvider>
</StyledEngineProvider>
</UserContext.Provider>
</UserProvider>
</EnvProvider>
</ReduxProvider>
);
Expand Down
47 changes: 47 additions & 0 deletions src/core/hooks/useRemoteList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { PayloadAction } from '@reduxjs/toolkit';

import shouldLoad from 'core/caching/shouldLoad';
import { RemoteList } from 'utils/storeUtils';
import { useAppDispatch } from '.';

export default function useRemoteList<
DataType,
OnLoadPayload = void,
OnSuccessPayload = DataType[]
>(
remoteList: RemoteList<DataType> | undefined,
hooks: {
actionOnError?: (err: unknown) => PayloadAction<unknown>;
actionOnLoad: () => PayloadAction<OnLoadPayload>;
actionOnSuccess: (items: DataType[]) => PayloadAction<OnSuccessPayload>;
isNecessary?: () => boolean;
loader: () => Promise<DataType[]>;
}
): DataType[] {
const dispatch = useAppDispatch();
const loadIsNecessary = hooks.isNecessary?.() ?? shouldLoad(remoteList);

if (!remoteList || loadIsNecessary) {
const promise = hooks
.loader()
.then((val) => {
dispatch(hooks.actionOnSuccess(val));
return val;
})
.catch((err: unknown) => {
if (hooks.actionOnError) {
dispatch(hooks.actionOnError(err));
return null;
} else {
throw err;
}
});

throw promise;
}

return remoteList.items
.filter((item) => !item.deleted)
.map((item) => item.data)
.filter((data) => !!data) as DataType[];
}
7 changes: 7 additions & 0 deletions src/core/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useContext } from 'react';

import { UserContext } from 'core/env/UserContext';

export default function useUser() {
return useContext(UserContext);
}
2 changes: 2 additions & 0 deletions src/core/rpc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import { renderEmailDef } from 'features/emails/rpc/renderEmail/server';
import { createCallAssignmentDef } from 'features/callAssignments/rpc/createCallAssignment';
import { getJoinFormEmbedDataDef } from 'features/joinForms/rpc/getJoinFormEmbedData';
import { createHouseholdsDef } from 'features/canvassAssignments/rpc/createHouseholds/server';
import { getAllEventsDef } from 'features/events/rpc/getAllEvents';

export function createRPCRouter() {
const rpcRouter = new RPCRouter();

rpcRouter.register(getAllEventsDef);
rpcRouter.register(deleteFolderRouteDef);
rpcRouter.register(createNewViewRouteDef);
rpcRouter.register(copyViewRouteDef);
Expand Down
18 changes: 18 additions & 0 deletions src/features/callAssignments/hooks/useMyCallAssignments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useApiClient, useAppSelector } from 'core/hooks';
import useRemoteList from 'core/hooks/useRemoteList';
import { userAssignmentsLoad, userAssignmentsLoaded } from '../store';
import { ZetkinCallAssignment } from 'utils/types/zetkin';

export default function useMyCallAssignments() {
const apiClient = useApiClient();
const list = useAppSelector(
(state) => state.callAssignments.userAssignmentList
);

return useRemoteList(list, {
actionOnLoad: () => userAssignmentsLoad(),
actionOnSuccess: (data) => userAssignmentsLoaded(data),
loader: () =>
apiClient.get<ZetkinCallAssignment[]>(`/api/users/me/call_assignments`),
});
}
14 changes: 14 additions & 0 deletions src/features/callAssignments/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface CallAssignmentSlice {
callersById: Record<number, RemoteList<CallAssignmentCaller>>;
callList: RemoteList<Call>;
statsById: Record<number, RemoteItem<CallAssignmentStats>>;
userAssignmentList: RemoteList<CallAssignmentData>;
}

const initialState: CallAssignmentSlice = {
Expand All @@ -30,6 +31,7 @@ const initialState: CallAssignmentSlice = {
callList: remoteList(),
callersById: {},
statsById: {},
userAssignmentList: remoteList(),
};

const callAssignmentsSlice = createSlice({
Expand Down Expand Up @@ -291,6 +293,16 @@ const callAssignmentsSlice = createSlice({
}
);
},
userAssignmentsLoad: (state) => {
state.userAssignmentList.isLoading = true;
},
userAssignmentsLoaded: (
state,
action: PayloadAction<CallAssignmentData[]>
) => {
state.userAssignmentList = remoteList(action.payload);
state.userAssignmentList.loaded = new Date().toISOString();
},
},
});

Expand Down Expand Up @@ -319,4 +331,6 @@ export const {
campaignCallAssignmentsLoaded,
statsLoad,
statsLoaded,
userAssignmentsLoad,
userAssignmentsLoaded,
} = callAssignmentsSlice.actions;
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const CanvasserSidebar: FC<Props> = ({ assignment }) => {
</Box>
</Box>
<List>
<ListItemButton href="/my/canvassassignments" sx={{ px: 1 }}>
<ListItemButton href="/my/home" sx={{ px: 1 }}>
<ListItemText primary="My assignments" />
</ListItemButton>
<ListItemButton href="/logout" sx={{ px: 1 }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ type MyCanvassAssignmentPageProps = {
const MyCanvassAssignmentPage: FC<MyCanvassAssignmentPageProps> = ({
canvassAssId,
}) => {
const myAssignments = useMyCanvassAssignments().data || [];
const myAssignments = useMyCanvassAssignments();
const assignment = myAssignments.find(
(assignment) => assignment.id == canvassAssId
);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { loadListIfNecessary } from 'core/caching/cacheUtils';
import { useApiClient, useAppDispatch, useAppSelector } from 'core/hooks';
import { useApiClient, useAppSelector } from 'core/hooks';
import { myAssignmentsLoad, myAssignmentsLoaded } from '../store';
import { AssignmentWithAreas } from '../types';
import useRemoteList from 'core/hooks/useRemoteList';

export default function useMyCanvassAssignments() {
const apiClient = useApiClient();
const dispatch = useAppDispatch();
const mySessions = useAppSelector(
const assignments = useAppSelector(
(state) => state.canvassAssignments.myAssignmentsWithAreasList
);

return loadListIfNecessary(mySessions, dispatch, {
return useRemoteList(assignments, {
actionOnLoad: () => myAssignmentsLoad(),
actionOnSuccess: (data) => myAssignmentsLoaded(data),
loader: () =>
Expand Down
2 changes: 1 addition & 1 deletion src/features/emails/hooks/useSendTestEmail.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';

import { useUser } from 'utils/hooks/useFocusDate';
import useUser from 'core/hooks/useUser';
import { useApiClient, useNumericRouteParams } from 'core/hooks';

export default function useSendTestEmail() {
Expand Down
15 changes: 15 additions & 0 deletions src/features/events/hooks/useAllEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useApiClient, useAppSelector } from 'core/hooks';
import useRemoteList from 'core/hooks/useRemoteList';
import { allEventsLoad, allEventsLoaded } from '../store';
import getAllEvents from '../rpc/getAllEvents';

export default function useAllEvents() {
const apiClient = useApiClient();
const allEventsList = useAppSelector((state) => state.events.allEventsList);

return useRemoteList(allEventsList, {
actionOnLoad: () => allEventsLoad(),
actionOnSuccess: (data) => allEventsLoaded(data),
loader: () => apiClient.rpc(getAllEvents, {}),
});
}
15 changes: 15 additions & 0 deletions src/features/events/hooks/useMyEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useApiClient, useAppSelector } from 'core/hooks';
import useRemoteList from 'core/hooks/useRemoteList';
import { userEventsLoad, userEventsLoaded } from '../store';
import { ZetkinEvent } from 'utils/types/zetkin';

export default function useMyEvents() {
const apiClient = useApiClient();
const list = useAppSelector((state) => state.events.userEventList);

return useRemoteList(list, {
actionOnLoad: () => userEventsLoad(),
actionOnSuccess: (data) => userEventsLoaded(data),
loader: () => apiClient.get<ZetkinEvent[]>(`/api/users/me/actions`),
});
}
Loading
Loading