Skip to content

Commit

Permalink
fix: invalidate activities list when consent is accepted
Browse files Browse the repository at this point in the history
  • Loading branch information
swain committed Dec 2, 2023
1 parent 57b28d2 commit 9a8f36b
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 85 deletions.
16 changes: 7 additions & 9 deletions src/hooks/useActivities.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useCallback } from 'react';
import { gql } from 'graphql-request';
import { useGraphQLClient } from './useGraphQLClient';
import { useQuery } from '@tanstack/react-query';
Expand Down Expand Up @@ -364,15 +363,14 @@ type ActivitiesQueryResponse = {
};
};

export const ACTIVITIES_QUERY_KEY = ['activities'];

export const useActivities = (input: ActivitiesInput) => {
const { graphQLClient } = useGraphQLClient();

const queryForActivities = useCallback(async () => {
return graphQLClient.request<ActivitiesQueryResponse>(
getActivitiesQueryDocument,
{ input },
);
}, [graphQLClient, input]);

return useQuery(['activities'], queryForActivities);
return useQuery(ACTIVITIES_QUERY_KEY, () =>
graphQLClient.request<ActivitiesQueryResponse>(getActivitiesQueryDocument, {
input,
}),
);
};
18 changes: 8 additions & 10 deletions src/hooks/useConsent.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { renderHook, waitFor, act } from '@testing-library/react-native';
import { useConsent } from './useConsent';
import { createConsentPatch, useConsent } from './useConsent';
import { useHttpClient } from './useHttpClient';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
Expand All @@ -25,7 +25,7 @@ jest.mock('./useHttpClient', () => ({
const useActiveProjectMock = useActiveProject as jest.Mock;
const useHttpClientMock = useHttpClient as jest.Mock;

const renderHookInContext = (useHook: Function) => {
const renderHookInContext = <T extends any>(useHook: () => T) => {
return renderHook(() => useHook(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
Expand Down Expand Up @@ -87,10 +87,9 @@ describe('useUpdateProjectConsentDirective', () => {

const { result } = renderHookInContext(useTestHook);
await act(async () => {
await result.current.mutateAsync({
directiveId: 'directive-id',
accept: true,
});
await result.current.mutateAsync(
createConsentPatch('directive-id', true),
);
});

expect(onSuccess).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -127,10 +126,9 @@ describe('useUpdateProjectConsentDirective', () => {

const { result } = renderHookInContext(useTestHook);
await act(async () => {
await result.current.mutateAsync({
directiveId: 'directive-id',
accept: false,
});
await result.current.mutateAsync(
createConsentPatch('directive-id', false),
);
});

expect(axiosMock.history.patch[0].url).toBe(
Expand Down
68 changes: 27 additions & 41 deletions src/hooks/useConsent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,32 @@ import { useActiveProject } from './useActiveProject';
import { Consent, Questionnaire } from 'fhir/r3';
import { useRestQuery, useRestMutation } from './rest-api';
import { RestAPIEndpoints } from '../types/rest-types';
import { RequestPayloadOf } from '@lifeomic/one-query';
import { useQueryClient } from '@tanstack/react-query';
import { ACTIVITIES_QUERY_KEY } from './useActivities';

type PatchConsentDirectives =
RestAPIEndpoints['PATCH /v1/consent/directives/me/:directiveId'];

export const createConsentPatch = (
directiveId: string,
accept: boolean,
): RequestPayloadOf<
RestAPIEndpoints,
'PATCH /v1/consent/directives/me/:directiveId'
> => ({
directiveId,
status: accept ? 'active' : 'rejected',
response: {
item: [
{ linkId: 'terms' },
{ linkId: 'acceptance', answer: [{ valueBoolean: accept }] },
],
},
});

export const useConsent = () => {
const queryClient = useQueryClient();
const { activeProject } = useActiveProject();

const useConsentDirectives = () => {
Expand All @@ -24,42 +45,12 @@ export const useConsent = () => {
},
) => Promise<void> | void;
}) => {
const mutation = useRestMutation(
'PATCH /v1/consent/directives/me/:directiveId',
options,
);

const getInput = ({ directiveId, accept }: ConsentPatch) => {
const status: 'active' | 'rejected' = accept ? 'active' : 'rejected';
return {
directiveId,
status,
response: {
item: [
{
linkId: 'terms',
},
{
linkId: 'acceptance',
answer: [
{
valueBoolean: accept,
},
],
},
],
},
} as PatchConsentDirectives['Request'] & {
directiveId: string;
};
};

return {
...mutation,
mutate: (values: ConsentPatch) => mutation.mutate(getInput(values)),
mutateAsync: (values: ConsentPatch) =>
mutation.mutateAsync(getInput(values)),
};
return useRestMutation('PATCH /v1/consent/directives/me/:directiveId', {
onSuccess: async (data, variables) => {
queryClient.resetQueries({ queryKey: ACTIVITIES_QUERY_KEY });
await options?.onSuccess?.(data, variables);
},
});
};

const useShouldRenderConsentScreen = () => {
Expand Down Expand Up @@ -88,11 +79,6 @@ export const useConsent = () => {
};
};

type ConsentPatch = {
directiveId: string;
accept: boolean;
};

export type ConsentAndForm = Consent & {
form: Questionnaire;
};
43 changes: 22 additions & 21 deletions src/screens/ConsentScreen.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React from 'react';
import { fireEvent, render } from '@testing-library/react-native';
import { Alert } from 'react-native';
import { useOAuthFlow, useConsent, useOnboardingCourse } from '../hooks';
import {
useOAuthFlow,
useConsent,
useOnboardingCourse,
createConsentPatch,
} from '../hooks';
import { ConsentScreen } from './ConsentScreen';
import { useDeveloperConfig } from '../hooks';

Expand All @@ -11,6 +16,7 @@ jest.mock('../hooks/useOAuthFlow', () => ({
useOAuthFlow: jest.fn(),
}));
jest.mock('../hooks/useConsent', () => ({
...jest.requireActual('../hooks/useConsent'),
useConsent: jest.fn(),
}));
jest.mock('../hooks/useOnboardingCourse', () => ({
Expand Down Expand Up @@ -135,10 +141,9 @@ test('renders custom consent screen if present in developer config', () => {
});
expect(navigateMock.replace).toHaveBeenCalledWith('app');
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledTimes(1);
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith({
directiveId: defaultConsentDirective.id,
accept: true,
});
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith(
createConsentPatch(defaultConsentDirective.id, true),
);

// reset for later assertions
updateConsentDirectiveMutationMock.mutate.mockClear();
Expand All @@ -151,10 +156,9 @@ test('renders custom consent screen if present in developer config', () => {
});
() => expect(logoutMock).toHaveBeenCalledTimes(1);
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledTimes(1);
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith({
directiveId: defaultConsentDirective.id,
accept: false,
});
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith(
createConsentPatch(defaultConsentDirective.id, false),
);

// check passed loading state
useUpdateProjectConsentDirectiveMock.mockReturnValue({
Expand Down Expand Up @@ -187,10 +191,9 @@ test('renders the consent body and acceptance verbiage', () => {
test('should accept the consent and navigate to the home screen', () => {
const { getByText } = render(consentScreen);
fireEvent.press(getByText('Agree'));
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith({
directiveId: defaultConsentDirective.id,
accept: true,
});
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith(
createConsentPatch(defaultConsentDirective.id, true),
);
useUpdateProjectConsentDirectiveMock.mock.calls[0][0].onSuccess(undefined, {
status: 'active',
});
Expand All @@ -203,10 +206,9 @@ test('should accept the consent and navigate to the onboarding course screen', (
});
const { getByText } = render(consentScreen);
fireEvent.press(getByText('Agree'));
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith({
directiveId: defaultConsentDirective.id,
accept: true,
});
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith(
createConsentPatch(defaultConsentDirective.id, true),
);
useUpdateProjectConsentDirectiveMock.mock.calls[0][0].onSuccess(undefined, {
status: 'active',
});
Expand All @@ -225,10 +227,9 @@ test('Pressing logout declines the consent and logs the the user out', async ()
const { getByText } = render(consentScreen);
fireEvent.press(getByText('Decline'));
alertSpy.mock.calls[0]?.[2]?.[1].onPress!();
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith({
directiveId: defaultConsentDirective.id,
accept: false,
});
expect(updateConsentDirectiveMutationMock.mutate).toHaveBeenCalledWith(
createConsentPatch(defaultConsentDirective.id, false),
);
useUpdateProjectConsentDirectiveMock.mock.calls[0][0].onSuccess(undefined, {
status: 'rejected',
});
Expand Down
8 changes: 4 additions & 4 deletions src/screens/ConsentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
useConsent,
useOAuthFlow,
useOnboardingCourse,
createConsentPatch,
} from '../hooks';
import type { ConsentAndForm } from '../hooks/useConsent';
import { useDeveloperConfig } from '../hooks/useDeveloperConfig';
Expand Down Expand Up @@ -49,10 +50,9 @@ export const ConsentScreen = ({
if (!consentToPresent?.id) {
return;
}
updateConsentDirectiveMutation.mutate({
directiveId: consentToPresent.id,
accept,
});
updateConsentDirectiveMutation.mutate(
createConsentPatch(consentToPresent.id, accept),
);
},
[updateConsentDirectiveMutation, consentToPresent],
);
Expand Down

0 comments on commit 9a8f36b

Please sign in to comment.