Skip to content

Commit

Permalink
Merge pull request #1011 from CruGlobal/appeal-list-filters
Browse files Browse the repository at this point in the history
Appeal list filters
  • Loading branch information
dr-bizz authored Aug 28, 2024
2 parents 3ce23f2 + 2e837dc commit ab981ab
Show file tree
Hide file tree
Showing 25 changed files with 943 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { VirtuosoMockContext } from 'react-virtuoso';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { ListHeaderCheckBoxState } from 'src/components/Shared/Header/ListHeader';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/appealInfo.generated';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/AppealInfo.generated';
import { ContactsQuery } from 'src/components/Tool/Appeal/AppealsContext/contacts.generated';
import {
PledgeFrequencyEnum,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { VirtuosoMockContext } from 'react-virtuoso';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { ListHeaderCheckBoxState } from 'src/components/Shared/Header/ListHeader';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/appealInfo.generated';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/AppealInfo.generated';
import { ContactsQuery } from 'src/components/Tool/Appeal/AppealsContext/contacts.generated';
import {
PledgeFrequencyEnum,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ const onChange = jest.fn();

interface TestComponentProps {
value?: string[];
excludeContactIds?: string[];
}

const TestComponent: React.FC<TestComponentProps> = ({ value = [] }) => (
const TestComponent: React.FC<TestComponentProps> = ({
value = [],
excludeContactIds = [],
}) => (
<GqlMockedProvider<{
ContactOptions: ContactOptionsQuery;
}>
Expand All @@ -34,6 +38,7 @@ const TestComponent: React.FC<TestComponentProps> = ({ value = [] }) => (
accountListId={accountListId}
value={value}
onChange={onChange}
excludeContactIds={excludeContactIds}
/>
</GqlMockedProvider>
);
Expand All @@ -46,13 +51,13 @@ describe('ContactsAutocomplete', () => {
expect(await findByRole('option', { name: 'Alice' })).toBeInTheDocument();

expect(mutationSpy).toHaveBeenCalledTimes(1);
expect(mutationSpy.mock.calls[0][0].operation).toMatchObject({
operationName: 'ContactOptions',
variables: {
accountListId,
first: 10,
contactsFilters: { wildcardSearch: '' },
},
expect(mutationSpy.mock.lastCall[0].operation.operationName).toEqual(
'ContactOptions',
);
expect(mutationSpy.mock.lastCall[0].operation.variables).toEqual({
accountListId,
first: 10,
contactsFilters: { wildcardSearch: '' },
});
});

Expand All @@ -62,21 +67,22 @@ describe('ContactsAutocomplete', () => {
);

await waitFor(() => expect(mutationSpy).toHaveBeenCalledTimes(2));
expect(mutationSpy.mock.calls[0][0].operation).toMatchObject({
operationName: 'ContactOptions',
variables: {
accountListId,
first: 10,
contactsFilters: { wildcardSearch: '' },
},
expect(mutationSpy.mock.calls[0][0].operation.operationName).toEqual(
'ContactOptions',
);
expect(mutationSpy.mock.calls[0][0].operation.variables).toEqual({
accountListId,
first: 10,
contactsFilters: { wildcardSearch: '' },
});
expect(mutationSpy.mock.calls[1][0].operation).toMatchObject({
operationName: 'ContactOptions',
variables: {
accountListId,
first: 2,
contactsFilters: { ids: ['contact-1', 'contact-2'] },
},

expect(mutationSpy.mock.lastCall[0].operation.operationName).toEqual(
'ContactOptions',
);
expect(mutationSpy.mock.lastCall[0].operation.variables).toEqual({
accountListId,
first: 2,
contactsFilters: { ids: ['contact-1', 'contact-2'] },
});

userEvent.click(getByRole('combobox', { name: 'Contacts' }));
Expand All @@ -89,13 +95,13 @@ describe('ContactsAutocomplete', () => {
userEvent.type(getByRole('combobox', { name: 'Contacts' }), 'Search');

await waitFor(() => expect(mutationSpy).toHaveBeenCalledTimes(2));
expect(mutationSpy.mock.calls[1][0].operation).toMatchObject({
operationName: 'ContactOptions',
variables: {
accountListId,
first: 10,
contactsFilters: { wildcardSearch: 'Search' },
},
expect(mutationSpy.mock.lastCall[0].operation.operationName).toEqual(
'ContactOptions',
);
expect(mutationSpy.mock.lastCall[0].operation.variables).toEqual({
accountListId,
first: 10,
contactsFilters: { wildcardSearch: 'Search' },
});
});

Expand All @@ -120,4 +126,21 @@ describe('ContactsAutocomplete', () => {

expect(onChange).not.toHaveBeenCalled();
});

it('should limit what Ids it brings back', async () => {
render(<TestComponent value={[]} excludeContactIds={['contact-1']} />);

await waitFor(() => {
expect(mutationSpy).toHaveBeenCalledTimes(1);
expect(mutationSpy.mock.lastCall[0].operation.variables).toEqual({
accountListId: 'account-list-1',
first: 10,
contactsFilters: {
wildcardSearch: '',
ids: ['contact-1'],
reverseIds: true,
},
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ interface ContactsAutocompleteProps {
accountListId: string;
value: string[];
onChange: (value: string[]) => void;
excludeContactIds?: string[];
disabled?: boolean;
}

export const ContactsAutocomplete: React.FC<ContactsAutocompleteProps> = ({
accountListId,
value,
onChange,
excludeContactIds = [],
disabled = false,
}) => {
const { t } = useTranslation();

Expand All @@ -27,6 +31,15 @@ export const ContactsAutocomplete: React.FC<ContactsAutocompleteProps> = ({

// There are too many contacts to display all of them as options, so we load the contacts that
// the user has selected and the contacts matching the user's current search, and merge the results

const contactsFilters = excludeContactIds.length
? {
wildcardSearch: searchTerm,
ids: excludeContactIds,
reverseIds: true,
}
: { wildcardSearch: searchTerm };

const {
data: currentSearchedContacts,
previousData: previousSearchedContacts,
Expand All @@ -35,7 +48,7 @@ export const ContactsAutocomplete: React.FC<ContactsAutocompleteProps> = ({
variables: {
accountListId,
first: 10,
contactsFilters: { wildcardSearch: searchTerm },
contactsFilters,
},
});
// When this query loads contacts once and the user changes the search query, `data` will be
Expand Down Expand Up @@ -76,6 +89,7 @@ export const ContactsAutocomplete: React.FC<ContactsAutocompleteProps> = ({
multiple
openOnFocus
autoSelect
disabled={disabled}
options={options
.slice()
.sort((a, b) => a.name.localeCompare(b.name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
} from '../../AppealsContext/AppealsContext';
import { DynamicContactFlow } from '../../Flow/DynamicContactFlow';
import { DynamicContactsList } from '../../List/ContactsList/DynamicContactsList';
import { useAppealQuery } from './AppealInfo.generated';
import { AppealsMainPanelHeader } from './AppealsMainPanelHeader';
import { useAppealQuery } from './appealInfo.generated';

export const AppealsMainPanel: React.FC = () => {
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useAccountListId } from 'src/hooks/useAccountListId';
import {
AppealDocument,
AppealQuery,
} from '../AppealsMainPanel/appealInfo.generated';
} from '../AppealsMainPanel/AppealInfo.generated';
import { useUpdateAppealMutation } from './EditAppeal.generated';

interface EditAppealHeaderInfoModalProps {
Expand Down
88 changes: 87 additions & 1 deletion src/components/Tool/Appeal/AppealsContext/AppealsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useAccountListId } from 'src/hooks/useAccountListId';
import { useMassSelection } from 'src/hooks/useMassSelection';
import { sanitizeFilters } from 'src/lib/sanitizeFilters';
import { useContactsQuery } from './contacts.generated';
import { useContactsCountQuery } from './contactsCount.generated';

export enum AppealStatusEnum {
Excluded = 'excluded',
Expand All @@ -30,6 +31,19 @@ export enum TableViewModeEnum {
Flows = 'flows',
}

export const shouldSkipContactCount = (
filterPanelOpen: boolean,
viewMode: TableViewModeEnum,
) => {
if (viewMode === TableViewModeEnum.Flows) {
return true;
} else if (viewMode === TableViewModeEnum.List && !filterPanelOpen) {
return false;
} else {
return false;
}
};

export interface AppealsType
extends Omit<
ContactsType,
Expand All @@ -47,6 +61,11 @@ export interface AppealsType
contactsQueryResult: ReturnType<typeof useContactsQuery>;
appealId: string | undefined;
page: PageEnum | undefined;
askedCountQueryResult: ReturnType<typeof useContactsCountQuery>;
excludedCountQueryResult: ReturnType<typeof useContactsCountQuery>;
committedCountQueryResult: ReturnType<typeof useContactsCountQuery>;
givenCountQueryResult: ReturnType<typeof useContactsCountQuery>;
receivedCountQueryResult: ReturnType<typeof useContactsCountQuery>;
}

export const AppealsContext = React.createContext<AppealsType | null>(null);
Expand Down Expand Up @@ -122,7 +141,7 @@ export const AppealsProvider: React.FC<AppealsContextProps> = ({
ids: [],
appeal: [appealId || ''],
}),
[sanitizedFilters, starredFilter, searchTerm],
[sanitizedFilters, starredFilter, searchTerm, appealId],
);

const contactsQueryResult = useContactsQuery({
Expand Down Expand Up @@ -205,6 +224,68 @@ export const AppealsProvider: React.FC<AppealsContextProps> = ({
},
});

const nameSearch = searchTerm ? { wildcardSearch: searchTerm as string } : {};
const defaultFilters = {
appeal: [appealId || ''],
...nameSearch,
};
const skip = shouldSkipContactCount(filterPanelOpen, viewMode);

const askedCountQueryResult = useContactsCountQuery({
variables: {
accountListId: accountListId || '',
contactsFilter: {
...defaultFilters,
appealStatus: AppealStatusEnum.Asked,
},
},
skip,
});

const excludedCountQueryResult = useContactsCountQuery({
variables: {
accountListId: accountListId || '',
contactsFilter: {
...defaultFilters,
appealStatus: AppealStatusEnum.Excluded,
},
},
skip,
});

const committedCountQueryResult = useContactsCountQuery({
variables: {
accountListId: accountListId || '',
contactsFilter: {
...defaultFilters,
appealStatus: AppealStatusEnum.NotReceived,
},
},
skip,
});

const givenCountQueryResult = useContactsCountQuery({
variables: {
accountListId: accountListId || '',
contactsFilter: {
...defaultFilters,
appealStatus: AppealStatusEnum.Processed,
},
},
skip,
});

const receivedCountQueryResult = useContactsCountQuery({
variables: {
accountListId: accountListId || '',
contactsFilter: {
...defaultFilters,
appealStatus: AppealStatusEnum.ReceivedNotProcessed,
},
},
skip,
});

const toggleFilterPanel = () => {
setFilterPanelOpen(!filterPanelOpen);
};
Expand Down Expand Up @@ -363,6 +444,11 @@ export const AppealsProvider: React.FC<AppealsContextProps> = ({
userOptionsLoading: userOptionsLoading,
appealId,
page,
askedCountQueryResult,
excludedCountQueryResult,
committedCountQueryResult,
givenCountQueryResult,
receivedCountQueryResult,
}}
>
{children}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tool/Appeal/AppealsDetailsPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { AppealsWrapper } from 'pages/accountLists/[accountListId]/tools/appeals/AppealsWrapper';
import { ListHeaderCheckBoxState } from 'src/components/Shared/Header/ListHeader';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/appealInfo.generated';
import { AppealQuery } from 'src/components/Tool/Appeal/AppealDetails/AppealsMainPanel/AppealInfo.generated';
import { ContactsQuery } from 'src/components/Tool/Appeal/AppealsContext/contacts.generated';
import {
PledgeFrequencyEnum,
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tool/Appeal/Flow/ContactFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ContactFilterSetInput } from 'src/graphql/types.generated';
import i18n from 'src/lib/i18n';
import theme from 'src/theme';
import { AppealHeaderInfo } from '../AppealDetails/AppealHeaderInfo';
import { AppealQuery } from '../AppealDetails/AppealsMainPanel/appealInfo.generated';
import { AppealQuery } from '../AppealDetails/AppealsMainPanel/AppealInfo.generated';
import { AppealStatusEnum } from '../AppealsContext/AppealsContext';
import { ContactFlowColumn } from './ContactFlowColumn/ContactFlowColumn';

Expand Down
13 changes: 10 additions & 3 deletions src/components/Tool/Appeal/InitialPage/Appeals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,16 @@ const Appeals: React.FC<AppealsProps> = ({ accountListId }) => {
refetchQueries: [
{ query: GetAppealsDocument, variables: { accountListId } },
],
});
enqueueSnackbar(t('Primary Appeal Updated'), {
variant: 'success',
onCompleted: () => {
enqueueSnackbar(t('Appeal successfully set to primary'), {
variant: 'success',
});
},
onError: () => {
enqueueSnackbar(t('Unable to set appeal as primary'), {
variant: 'error',
});
},
});
};

Expand Down
Loading

0 comments on commit ab981ab

Please sign in to comment.