diff --git a/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.story.tsx b/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.story.tsx index c89ccc05c..24a8a1af9 100644 --- a/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.story.tsx +++ b/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.story.tsx @@ -24,6 +24,9 @@ export default meta type Story = StoryObj export const DefaultAdminMemberView: Story = { args: { - data: mockDataArray + data: mockDataArray, + handleResetMemberships() { + alert("YOU WANT TO RESET???") + } } } diff --git a/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.tsx b/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.tsx index e498e7f5f..45d6b5c84 100644 --- a/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.tsx +++ b/client/src/components/composite/Admin/AdminMemberView/AdminMemberView.tsx @@ -65,6 +65,13 @@ interface IAdminMemberView { * Used to indicate if there is currently an operation going on */ isUpdating?: boolean + + /** + * Method which makes relevant network call to make all + * non-admin users guests, which forces everyone to pay + * for a membership again + */ + handleResetMemberships?: () => void } /** @@ -101,7 +108,8 @@ export const AdminMemberView = ({ openAddMemberView, exportUserDataHandler, isUpdating, - hasNextPage + hasNextPage, + handleResetMemberships }: IAdminMemberView) => { /** * For use with `AdminSearchBar` @@ -194,7 +202,7 @@ export const AdminMemberView = ({
- + +
) } diff --git a/client/src/components/composite/Admin/AdminMemberView/ProtectedAdminMemberView.tsx b/client/src/components/composite/Admin/AdminMemberView/ProtectedAdminMemberView.tsx index df99ae992..92497903f 100644 --- a/client/src/components/composite/Admin/AdminMemberView/ProtectedAdminMemberView.tsx +++ b/client/src/components/composite/Admin/AdminMemberView/ProtectedAdminMemberView.tsx @@ -3,7 +3,8 @@ import { AdminMemberView, MemberColumnFormat } from "./AdminMemberView" import { useDeleteUserMutation, useDemoteUserMutation, - usePromoteUserMutation + usePromoteUserMutation, + useResetMembershipsMutation } from "@/services/Admin/AdminMutations" import { TableRowOperation } from "@/components/generic/ReusableTable/TableUtils" import AdminUserCreationModal, { @@ -37,6 +38,8 @@ const WrappedAdminMemberView = () => { */ const { mutateAsync: addNewUser } = useSignUpUserMutation("admin") + const { mutateAsync: resetAllMemberships } = useResetMembershipsMutation() + /** * https://stackoverflow.com/a/68066447 */ @@ -190,6 +193,15 @@ const WrappedAdminMemberView = () => { fetchNextPage={() => { !isFetchingNextPage && hasNextPage && fetchNextPage() }} + handleResetMemberships={async () => { + if ( + confirm( + "Are you SURE you want to reset all memberships for ALL members (they will have to pay for membership again)" + ) + ) { + await resetAllMemberships() + } + }} hasNextPage={hasNextPage} exportUserDataHandler={handleExportUsers} isUpdating={isPending} diff --git a/client/src/services/Admin/AdminMutations.ts b/client/src/services/Admin/AdminMutations.ts index 093d7b124..759d678e8 100644 --- a/client/src/services/Admin/AdminMutations.ts +++ b/client/src/services/Admin/AdminMutations.ts @@ -207,3 +207,16 @@ export function useDeleteEventMutation() { onSuccess: invalidateEventsQuery }) } + +export function useResetMembershipsMutation() { + return useMutation({ + mutationKey: ["reset-memberships"], + retry: false, + mutationFn: AdminService.resetMemberships, + onSuccess: () => { + queryClient.removeQueries({ + queryKey: [ALL_USERS_QUERY] + }) + } + }) +} diff --git a/client/src/services/Admin/AdminService.ts b/client/src/services/Admin/AdminService.ts index 48ff63219..0548a4d29 100644 --- a/client/src/services/Admin/AdminService.ts +++ b/client/src/services/Admin/AdminService.ts @@ -250,6 +250,13 @@ const AdminService = { if (!response.ok) { throw new Error(`Failed to delete event with id ${eventId}`) } + }, + resetMemberships: async function () { + const { response } = await fetchClient.PATCH("/admin/users/demote-all") + + if (!response.ok) { + throw new Error(`Failed to demote all users`) + } } } as const diff --git a/server/src/service-layer/controllers/AdminController.ts b/server/src/service-layer/controllers/AdminController.ts index de3021d8d..47cd00ae9 100644 --- a/server/src/service-layer/controllers/AdminController.ts +++ b/server/src/service-layer/controllers/AdminController.ts @@ -605,7 +605,7 @@ export class AdminController extends Controller { const authService = new AuthService() let allUsers: UserRecord[] = await authService.getAllUsers() allUsers = allUsers.filter( - (user) => !user.customClaims.admin && user.customClaims.member + (user) => !user.customClaims?.admin && user.customClaims?.member ) const demotePromises = await Promise.all( allUsers.map((user) => {