Skip to content

Commit

Permalink
feat: add password status hook (#958)
Browse files Browse the repository at this point in the history
* feat: add get password status hook

* fix: return data

* refactor: invalidate password status

* test: add test password status hook

* refactor: apply PR requested changes
  • Loading branch information
pyphilia authored Oct 11, 2024
1 parent 60e21e4 commit e1542e4
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { WebsocketClient } from '@graasp/sdk';
import configureItemHooks from '../item/hooks.js';
import configureItemPublicationHooks from '../item/publication/hooks.js';
import configureMemberHooks from '../member/hooks.js';
import configureMemberPasswordHooks from '../member/password/hooks.js';
import configurePublicProfileHooks from '../member/publicProfile/hooks.js';
import configureSubscriptionHooks from '../member/subscription/hooks.js';
import configureMembershipRequestHooks from '../membership/request/hooks.js';
Expand Down Expand Up @@ -62,6 +63,7 @@ export default (
...configureEmbeddedLinkHooks(queryConfig),
...configureItemPublicationHooks(queryConfig),
...configureMembershipRequestHooks(queryConfig),
...configureMemberPasswordHooks(queryConfig),
useDebounce,
};
};
3 changes: 3 additions & 0 deletions src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ export const memberKeys = {
],
// apps used mostly by the member
mostUsedApps: [...currentBaseKey, 'mostUsedApps'] as const,

// password status
passwordStatus: [...currentBaseKey, 'passwordStatus'],
};
},
};
Expand Down
11 changes: 9 additions & 2 deletions src/member/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ export default (queryConfig: QueryClientConfig) => {
* Mutation to create a member password
* @param {Password} password new password to set on current member
*/
const useCreatePassword = () =>
useMutation({
const useCreatePassword = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: { password: Password }) =>
Api.createPassword(payload, queryConfig),
onSuccess: () => {
Expand All @@ -195,7 +196,13 @@ export default (queryConfig: QueryClientConfig) => {
payload: { error },
});
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: memberKeys.current().passwordStatus,
});
},
});
};

const useUpdateMemberEmail = () =>
useMutation({
Expand Down
12 changes: 12 additions & 0 deletions src/member/password/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PartialQueryConfigForApi } from '../../types.js';
import { buildGetPasswordStatusRoute } from './routes.js';

export const getPasswordStatus = async ({
API_HOST,
axios,
}: PartialQueryConfigForApi) =>
axios
.get<{
hasPassword: boolean;
}>(`${API_HOST}/${buildGetPasswordStatusRoute()}`)
.then(({ data }) => data);
52 changes: 52 additions & 0 deletions src/member/password/hooks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { StatusCodes } from 'http-status-codes';
import nock from 'nock';
import { afterEach, describe, expect, it } from 'vitest';

import { UNAUTHORIZED_RESPONSE } from '../../../test/constants.js';
import { mockHook, setUpTest } from '../../../test/utils.js';
import { memberKeys } from '../../keys.js';
import { buildGetPasswordStatusRoute } from './routes.js';

const { hooks, wrapper, queryClient } = setUpTest();
describe('Member Hooks', () => {
afterEach(() => {
queryClient.clear();
nock.cleanAll();
});

describe('usePasswordStatus', () => {
const route = `/${buildGetPasswordStatusRoute()}`;
const hook = hooks.usePasswordStatus;
const key = memberKeys.current().passwordStatus;

it(`Receive password status`, async () => {
const response = { hasPassword: true };
const endpoints = [{ route, response }];
const { data } = await mockHook({ endpoints, hook, wrapper });

expect(data).toMatchObject(response);
// verify cache keys
expect(queryClient.getQueryData(key)).toMatchObject(data!);
});

it(`Unauthorized`, async () => {
const endpoints = [
{
route,
response: UNAUTHORIZED_RESPONSE,
statusCode: StatusCodes.UNAUTHORIZED,
},
];
const { data, isError } = await mockHook({
endpoints,
hook,
wrapper,
});

expect(data).toBeFalsy();

expect(isError).toBeTruthy();
expect(queryClient.getQueryData(key)).toBeFalsy();
});
});
});
18 changes: 18 additions & 0 deletions src/member/password/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useQuery } from '@tanstack/react-query';

import { memberKeys } from '../../keys.js';
import { QueryClientConfig } from '../../types.js';
import { getPasswordStatus } from './api.js';

export default (queryConfig: QueryClientConfig) => {
const { defaultQueryOptions } = queryConfig;

return {
usePasswordStatus: () =>
useQuery({
queryKey: memberKeys.current().passwordStatus,
queryFn: () => getPasswordStatus(queryConfig),
...defaultQueryOptions,
}),
};
};
4 changes: 4 additions & 0 deletions src/member/password/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { MEMBERS_ROUTE } from '../routes.js';

export const buildGetPasswordStatusRoute = () =>
`${MEMBERS_ROUTE}/current/password/status`;

0 comments on commit e1542e4

Please sign in to comment.