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

[MPDX-8240] Deselect removed ids #1151

Merged
merged 3 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 10 additions & 1 deletion pages/accountLists/[accountListId]/tasks/Tasks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event';
import { VirtuosoMockContext } from 'react-virtuoso';
import TestRouter from '__tests__/util/TestRouter';
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
import { GetTaskIdsForMassSelectionQuery } from 'src/hooks/GetIdsForMassSelection.generated';
import useTaskModal from 'src/hooks/useTaskModal';
import { dispatch } from 'src/lib/analytics';
import theme from 'src/theme';
Expand Down Expand Up @@ -141,7 +142,10 @@ describe('tasks page', () => {
it('should dispatch one analytics event per task', async () => {
const { getAllByTestId, getByRole, findByRole } = render(
<MocksProviders>
<GqlMockedProvider<{ Tasks: TasksQuery }>
<GqlMockedProvider<{
Tasks: TasksQuery;
GetTaskIdsForMassSelection: GetTaskIdsForMassSelectionQuery;
}>
mocks={{
Tasks: {
tasks: {
Expand All @@ -154,6 +158,11 @@ describe('tasks page', () => {
pageInfo: { hasNextPage: false },
},
},
GetTaskIdsForMassSelection: {
tasks: {
nodes: [{ id: '1' }, { id: '2' }, { id: '3' }],
},
},
}}
>
<Tasks />
Expand Down
23 changes: 12 additions & 11 deletions pages/accountLists/[accountListId]/tasks/[[...contactId]].page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,19 @@ const TasksPage: React.FC = () => {

//#region Mass Actions

const taskCount = data?.tasks.totalCount ?? 0;
const { data: allTasks } = useGetTaskIdsForMassSelectionQuery({
variables: {
accountListId,
first: taskCount,
tasksFilter,
},
skip: taskCount === 0,
});
const { data: allTasks, previousData: allTasksPrevious } =
useGetTaskIdsForMassSelectionQuery({
variables: {
accountListId,
tasksFilter,
},
});
// When the next batch of task ids is loading, use the previous batch of task ids in the
// meantime to avoid throwing out the selected task ids.
const allTaskIds = useMemo(
() => allTasks?.tasks.nodes.map((task) => task.id) ?? [],
[allTasks],
() =>
(allTasks ?? allTasksPrevious)?.tasks.nodes.map((task) => task.id) ?? [],
[allTasks, allTasksPrevious],
);

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,19 @@ export const ContactTasksTab: React.FC<ContactTasksTabProps> = ({
[starredFilter, searchTerm],
);
const taskCount = data?.tasks.totalCount ?? 0;
const { data: allTasks } = useGetTaskIdsForMassSelectionQuery({
variables: {
accountListId,
first: taskCount,
tasksFilter,
},
skip: taskCount === 0,
});
const { data: allTasks, previousData: allTasksPrevious } =
useGetTaskIdsForMassSelectionQuery({
variables: {
accountListId,
tasksFilter,
},
});
// When the next batch of task ids is loading, use the previous batch of task ids in the
// meantime to avoid throwing out the selected task ids.
const allTaskIds = useMemo(
() => allTasks?.tasks.nodes.map((task) => task.id) ?? [],
[allTasks],
() =>
(allTasks ?? allTasksPrevious)?.tasks.nodes.map((task) => task.id) ?? [],
[allTasks, allTasksPrevious],
);
//#region Mass Actions
const {
Expand Down
25 changes: 14 additions & 11 deletions src/components/Contacts/ContactsContext/ContactsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,21 @@ export const ContactsProvider: React.FC<ContactsContextProps> = ({

//#region Mass Actions

const contactCount = data?.contacts.totalCount ?? 0;
const { data: allContacts } = useGetIdsForMassSelectionQuery({
variables: {
accountListId,
first: contactCount,
contactsFilters,
},
skip: contactCount === 0,
});
const { data: allContacts, previousData: allContactsPrevious } =
useGetIdsForMassSelectionQuery({
variables: {
accountListId,
contactsFilters,
},
});
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
// meantime to avoid throwing out the selected contact ids.
const allContactIds = useMemo(
() => allContacts?.contacts.nodes.map((contact) => contact.id) ?? [],
[allContacts],
() =>
(allContacts ?? allContactsPrevious)?.contacts.nodes.map(
(contact) => contact.id,
) ?? [],
[allContacts, allContactsPrevious],
);

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,26 +88,28 @@ export const PartnerGivingAnalysisReport = forwardRef<
? Object.keys(activeFilters).length > 0
: false;

const { data, loading } = useGetPartnerGivingAnalysisReportQuery({
variables: {
input: {
accountListId,
// Page 1 is the first page for the API
page: page + 1,
pageSize: limit,
sortField: orderBy ?? '',
sortDirection:
order === 'asc'
? SortDirection.Ascending
: SortDirection.Descending,
contactFilters,
const { data, previousData, loading } =
useGetPartnerGivingAnalysisReportQuery({
variables: {
input: {
accountListId,
// Page 1 is the first page for the API
page: page + 1,
pageSize: limit,
sortField: orderBy ?? '',
sortDirection:
order === 'asc'
? SortDirection.Ascending
: SortDirection.Descending,
contactFilters,
},
},
},
});
});
const contacts = data?.partnerGivingAnalysisReport.contacts ?? [];

const contactCount = data?.partnerGivingAnalysisReport?.totalContacts ?? 0;
const { data: allContacts } =
const contactCount =
(data ?? previousData)?.partnerGivingAnalysisReport?.totalContacts ?? 0;
const { data: allContacts, previousData: allContactsPrevious } =
useGetPartnerGivingAnalysisIdsForMassSelectionQuery({
variables: {
input: {
Expand All @@ -121,12 +123,15 @@ export const PartnerGivingAnalysisReport = forwardRef<
},
skip: contactCount === 0,
});
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
// meantime to avoid throwing out the selected contact ids.
const allContactIds = useMemo(
() =>
allContacts?.partnerGivingAnalysisReport?.contacts.map(
(contact) => contact.id,
) ?? [],
[allContacts],
(
allContacts ?? allContactsPrevious
)?.partnerGivingAnalysisReport?.contacts.map((contact) => contact.id) ??
[],
[allContacts, allContactsPrevious],
);

const {
Expand Down
39 changes: 23 additions & 16 deletions src/components/Tool/Appeal/AppealsContext/AppealsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,38 +173,45 @@ export const AppealsProvider: React.FC<AppealsContextProps> = ({
},
skip: !accountListId,
});
const { data } = contactsQueryResult;

//#region Mass Actions

const contactCount = data?.contacts.totalCount ?? 0;
const { data: allContacts } = useGetIdsForMassSelectionQuery({
variables: {
accountListId,
first: contactCount,
contactsFilters,
},
skip: contactCount === 0,
});
const { data: allContacts, previousData: allContactsPrevious } =
useGetIdsForMassSelectionQuery({
variables: {
accountListId,
contactsFilters,
},
});
// In the flows view, we need the total count of all contacts in every column, but the API
// filters out contacts excluded from an appeal. We have to load excluded contacts also and
// manually merge them with the other contacts.
const { data: allExcludedContacts } = useGetIdsForMassSelectionQuery({
const {
data: allExcludedContacts,
previousData: allExcludedContactsPrevious,
} = useGetIdsForMassSelectionQuery({
variables: {
accountListId,
first: contactCount,
contactsFilters: { ...contactsFilters, appealStatus: 'excluded' },
},
// Skip this query when there is an appealStatus filter from the list view
skip: contactCount === 0 || !!contactsFilters.appealStatus,
skip: !!contactsFilters.appealStatus,
});
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
// meantime to avoid throwing out the selected contact ids.
const allContactIds = useMemo(
() =>
[
...(allContacts?.contacts.nodes ?? []),
...(allExcludedContacts?.contacts.nodes ?? []),
...((allContacts ?? allContactsPrevious)?.contacts.nodes ?? []),
...((allExcludedContacts ?? allExcludedContactsPrevious)?.contacts
.nodes ?? []),
].map((contact) => contact.id),
[allContacts, allExcludedContacts],
[
allContacts,
allContactsPrevious,
allExcludedContacts,
allExcludedContactsPrevious,
],
);

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,21 @@ export const ContactFlowColumn: React.FC<Props> = ({
skip: !accountListId || !appealStatus,
});

const contactCount = data?.contacts.totalCount ?? 0;
const { data: allContacts } = useGetIdsForMassSelectionQuery({
variables: {
accountListId,
first: contactCount,
contactsFilters,
},
skip: contactCount === 0,
});

const { data: allContacts, previousData: allContactsPrevious } =
useGetIdsForMassSelectionQuery({
variables: {
accountListId,
contactsFilters,
},
});
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
// meantime to avoid throwing out the selected contact ids.
const allContactIds = useMemo(
() => allContacts?.contacts.nodes.map((contact) => contact.id) ?? [],
[allContacts],
() =>
(allContacts ?? allContactsPrevious)?.contacts.nodes.map(
(contact) => contact.id,
) ?? [],
[allContacts, allContactsPrevious],
);

const { data: excludedContacts } = useExcludedAppealContactsQuery({
Expand Down
6 changes: 2 additions & 4 deletions src/hooks/GetIdsForMassSelection.graphql
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
query GetIdsForMassSelection(
$accountListId: ID!
$first: Int!
$contactsFilters: ContactFilterSetInput
) {
contacts(
accountListId: $accountListId
first: $first
contactsFilter: $contactsFilters
first: 20000 # Maximum allowed by the API
) {
nodes {
id
Expand All @@ -16,13 +15,12 @@ query GetIdsForMassSelection(

query GetTaskIdsForMassSelection(
$accountListId: ID!
$first: Int!
$tasksFilter: TaskFilterSetInput
) {
tasks(
accountListId: $accountListId
first: $first
tasksFilter: $tasksFilter
first: 1000 # Maximum allowed by the API
) {
nodes {
id
Expand Down
16 changes: 15 additions & 1 deletion src/hooks/useMassSelection.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react';
import { ListHeaderCheckBoxState } from 'src/components/Shared/Header/ListHeader';
import { useMassSelection } from './useMassSelection';
import { UseMassSelectionResult, useMassSelection } from './useMassSelection';

const defaultIdsList = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];

Expand Down Expand Up @@ -117,4 +117,18 @@ describe('useMassSelection', () => {
expect(result.current.ids).toEqual(['1', '2', '3', '7', '8', '9', '10']);
});
});

it('deselects removed ids', () => {
const { result, rerender } = renderHook<
UseMassSelectionResult,
{ ids: string[] }
>(({ ids }) => useMassSelection(ids), {
initialProps: { ids: defaultIdsList },
});

result.current.selectMultipleIds(['1', '2', '3']);

rerender({ ids: ['2', '3', '4'] });
expect(result.current.ids).toEqual(['2', '3']);
});
});
Loading
Loading