Skip to content

Commit ada0000

Browse files
authored
Merge pull request #1151 from CruGlobal/8240-deselect-removed-ids
[MPDX-8240] Deselect removed ids
2 parents 6c3cb0b + 6e9c8e4 commit ada0000

11 files changed

Lines changed: 153 additions & 105 deletions

File tree

pages/accountLists/[accountListId]/tasks/Tasks.test.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event';
55
import { VirtuosoMockContext } from 'react-virtuoso';
66
import TestRouter from '__tests__/util/TestRouter';
77
import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
8+
import { GetTaskIdsForMassSelectionQuery } from 'src/hooks/GetIdsForMassSelection.generated';
89
import useTaskModal from 'src/hooks/useTaskModal';
910
import { dispatch } from 'src/lib/analytics';
1011
import theme from 'src/theme';
@@ -141,7 +142,10 @@ describe('tasks page', () => {
141142
it('should dispatch one analytics event per task', async () => {
142143
const { getAllByTestId, getByRole, findByRole } = render(
143144
<MocksProviders>
144-
<GqlMockedProvider<{ Tasks: TasksQuery }>
145+
<GqlMockedProvider<{
146+
Tasks: TasksQuery;
147+
GetTaskIdsForMassSelection: GetTaskIdsForMassSelectionQuery;
148+
}>
145149
mocks={{
146150
Tasks: {
147151
tasks: {
@@ -154,6 +158,11 @@ describe('tasks page', () => {
154158
pageInfo: { hasNextPage: false },
155159
},
156160
},
161+
GetTaskIdsForMassSelection: {
162+
tasks: {
163+
nodes: [{ id: '1' }, { id: '2' }, { id: '3' }],
164+
},
165+
},
157166
}}
158167
>
159168
<Tasks />

pages/accountLists/[accountListId]/tasks/[[...contactId]].page.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,18 +184,19 @@ const TasksPage: React.FC = () => {
184184

185185
//#region Mass Actions
186186

187-
const taskCount = data?.tasks.totalCount ?? 0;
188-
const { data: allTasks } = useGetTaskIdsForMassSelectionQuery({
189-
variables: {
190-
accountListId,
191-
first: taskCount,
192-
tasksFilter,
193-
},
194-
skip: taskCount === 0,
195-
});
187+
const { data: allTasks, previousData: allTasksPrevious } =
188+
useGetTaskIdsForMassSelectionQuery({
189+
variables: {
190+
accountListId,
191+
tasksFilter,
192+
},
193+
});
194+
// When the next batch of task ids is loading, use the previous batch of task ids in the
195+
// meantime to avoid throwing out the selected task ids.
196196
const allTaskIds = useMemo(
197-
() => allTasks?.tasks.nodes.map((task) => task.id) ?? [],
198-
[allTasks],
197+
() =>
198+
(allTasks ?? allTasksPrevious)?.tasks.nodes.map((task) => task.id) ?? [],
199+
[allTasks, allTasksPrevious],
199200
);
200201

201202
const {

src/components/Contacts/ContactDetails/ContactTasksTab/ContactTasksTab.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,17 +137,19 @@ export const ContactTasksTab: React.FC<ContactTasksTabProps> = ({
137137
[starredFilter, searchTerm],
138138
);
139139
const taskCount = data?.tasks.totalCount ?? 0;
140-
const { data: allTasks } = useGetTaskIdsForMassSelectionQuery({
141-
variables: {
142-
accountListId,
143-
first: taskCount,
144-
tasksFilter,
145-
},
146-
skip: taskCount === 0,
147-
});
140+
const { data: allTasks, previousData: allTasksPrevious } =
141+
useGetTaskIdsForMassSelectionQuery({
142+
variables: {
143+
accountListId,
144+
tasksFilter,
145+
},
146+
});
147+
// When the next batch of task ids is loading, use the previous batch of task ids in the
148+
// meantime to avoid throwing out the selected task ids.
148149
const allTaskIds = useMemo(
149-
() => allTasks?.tasks.nodes.map((task) => task.id) ?? [],
150-
[allTasks],
150+
() =>
151+
(allTasks ?? allTasksPrevious)?.tasks.nodes.map((task) => task.id) ?? [],
152+
[allTasks, allTasksPrevious],
151153
);
152154
//#region Mass Actions
153155
const {

src/components/Contacts/ContactsContext/ContactsContext.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,21 @@ export const ContactsProvider: React.FC<ContactsContextProps> = ({
186186

187187
//#region Mass Actions
188188

189-
const contactCount = data?.contacts.totalCount ?? 0;
190-
const { data: allContacts } = useGetIdsForMassSelectionQuery({
191-
variables: {
192-
accountListId,
193-
first: contactCount,
194-
contactsFilters,
195-
},
196-
skip: contactCount === 0,
197-
});
189+
const { data: allContacts, previousData: allContactsPrevious } =
190+
useGetIdsForMassSelectionQuery({
191+
variables: {
192+
accountListId,
193+
contactsFilters,
194+
},
195+
});
196+
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
197+
// meantime to avoid throwing out the selected contact ids.
198198
const allContactIds = useMemo(
199-
() => allContacts?.contacts.nodes.map((contact) => contact.id) ?? [],
200-
[allContacts],
199+
() =>
200+
(allContacts ?? allContactsPrevious)?.contacts.nodes.map(
201+
(contact) => contact.id,
202+
) ?? [],
203+
[allContacts, allContactsPrevious],
201204
);
202205

203206
const {

src/components/Reports/PartnerGivingAnalysisReport/PartnerGivingAnalysisReport.tsx

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,28 @@ export const PartnerGivingAnalysisReport = forwardRef<
8888
? Object.keys(activeFilters).length > 0
8989
: false;
9090

91-
const { data, loading } = useGetPartnerGivingAnalysisReportQuery({
92-
variables: {
93-
input: {
94-
accountListId,
95-
// Page 1 is the first page for the API
96-
page: page + 1,
97-
pageSize: limit,
98-
sortField: orderBy ?? '',
99-
sortDirection:
100-
order === 'asc'
101-
? SortDirection.Ascending
102-
: SortDirection.Descending,
103-
contactFilters,
91+
const { data, previousData, loading } =
92+
useGetPartnerGivingAnalysisReportQuery({
93+
variables: {
94+
input: {
95+
accountListId,
96+
// Page 1 is the first page for the API
97+
page: page + 1,
98+
pageSize: limit,
99+
sortField: orderBy ?? '',
100+
sortDirection:
101+
order === 'asc'
102+
? SortDirection.Ascending
103+
: SortDirection.Descending,
104+
contactFilters,
105+
},
104106
},
105-
},
106-
});
107+
});
107108
const contacts = data?.partnerGivingAnalysisReport.contacts ?? [];
108109

109-
const contactCount = data?.partnerGivingAnalysisReport?.totalContacts ?? 0;
110-
const { data: allContacts } =
110+
const contactCount =
111+
(data ?? previousData)?.partnerGivingAnalysisReport?.totalContacts ?? 0;
112+
const { data: allContacts, previousData: allContactsPrevious } =
111113
useGetPartnerGivingAnalysisIdsForMassSelectionQuery({
112114
variables: {
113115
input: {
@@ -121,12 +123,15 @@ export const PartnerGivingAnalysisReport = forwardRef<
121123
},
122124
skip: contactCount === 0,
123125
});
126+
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
127+
// meantime to avoid throwing out the selected contact ids.
124128
const allContactIds = useMemo(
125129
() =>
126-
allContacts?.partnerGivingAnalysisReport?.contacts.map(
127-
(contact) => contact.id,
128-
) ?? [],
129-
[allContacts],
130+
(
131+
allContacts ?? allContactsPrevious
132+
)?.partnerGivingAnalysisReport?.contacts.map((contact) => contact.id) ??
133+
[],
134+
[allContacts, allContactsPrevious],
130135
);
131136

132137
const {

src/components/Tool/Appeal/AppealsContext/AppealsContext.tsx

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -173,38 +173,45 @@ export const AppealsProvider: React.FC<AppealsContextProps> = ({
173173
},
174174
skip: !accountListId,
175175
});
176-
const { data } = contactsQueryResult;
177176

178177
//#region Mass Actions
179178

180-
const contactCount = data?.contacts.totalCount ?? 0;
181-
const { data: allContacts } = useGetIdsForMassSelectionQuery({
182-
variables: {
183-
accountListId,
184-
first: contactCount,
185-
contactsFilters,
186-
},
187-
skip: contactCount === 0,
188-
});
179+
const { data: allContacts, previousData: allContactsPrevious } =
180+
useGetIdsForMassSelectionQuery({
181+
variables: {
182+
accountListId,
183+
contactsFilters,
184+
},
185+
});
189186
// In the flows view, we need the total count of all contacts in every column, but the API
190187
// filters out contacts excluded from an appeal. We have to load excluded contacts also and
191188
// manually merge them with the other contacts.
192-
const { data: allExcludedContacts } = useGetIdsForMassSelectionQuery({
189+
const {
190+
data: allExcludedContacts,
191+
previousData: allExcludedContactsPrevious,
192+
} = useGetIdsForMassSelectionQuery({
193193
variables: {
194194
accountListId,
195-
first: contactCount,
196195
contactsFilters: { ...contactsFilters, appealStatus: 'excluded' },
197196
},
198197
// Skip this query when there is an appealStatus filter from the list view
199-
skip: contactCount === 0 || !!contactsFilters.appealStatus,
198+
skip: !!contactsFilters.appealStatus,
200199
});
200+
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
201+
// meantime to avoid throwing out the selected contact ids.
201202
const allContactIds = useMemo(
202203
() =>
203204
[
204-
...(allContacts?.contacts.nodes ?? []),
205-
...(allExcludedContacts?.contacts.nodes ?? []),
205+
...((allContacts ?? allContactsPrevious)?.contacts.nodes ?? []),
206+
...((allExcludedContacts ?? allExcludedContactsPrevious)?.contacts
207+
.nodes ?? []),
206208
].map((contact) => contact.id),
207-
[allContacts, allExcludedContacts],
209+
[
210+
allContacts,
211+
allContactsPrevious,
212+
allExcludedContacts,
213+
allExcludedContactsPrevious,
214+
],
208215
);
209216

210217
const {

src/components/Tool/Appeal/Flow/ContactFlowColumn/ContactFlowColumn.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,21 @@ export const ContactFlowColumn: React.FC<Props> = ({
100100
skip: !accountListId || !appealStatus,
101101
});
102102

103-
const contactCount = data?.contacts.totalCount ?? 0;
104-
const { data: allContacts } = useGetIdsForMassSelectionQuery({
105-
variables: {
106-
accountListId,
107-
first: contactCount,
108-
contactsFilters,
109-
},
110-
skip: contactCount === 0,
111-
});
112-
103+
const { data: allContacts, previousData: allContactsPrevious } =
104+
useGetIdsForMassSelectionQuery({
105+
variables: {
106+
accountListId,
107+
contactsFilters,
108+
},
109+
});
110+
// When the next batch of contact ids is loading, use the previous batch of contact ids in the
111+
// meantime to avoid throwing out the selected contact ids.
113112
const allContactIds = useMemo(
114-
() => allContacts?.contacts.nodes.map((contact) => contact.id) ?? [],
115-
[allContacts],
113+
() =>
114+
(allContacts ?? allContactsPrevious)?.contacts.nodes.map(
115+
(contact) => contact.id,
116+
) ?? [],
117+
[allContacts, allContactsPrevious],
116118
);
117119

118120
const { data: excludedContacts } = useExcludedAppealContactsQuery({

src/hooks/GetIdsForMassSelection.graphql

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
query GetIdsForMassSelection(
22
$accountListId: ID!
3-
$first: Int!
43
$contactsFilters: ContactFilterSetInput
54
) {
65
contacts(
76
accountListId: $accountListId
8-
first: $first
97
contactsFilter: $contactsFilters
8+
first: 20000 # Maximum allowed by the API
109
) {
1110
nodes {
1211
id
@@ -16,13 +15,12 @@ query GetIdsForMassSelection(
1615

1716
query GetTaskIdsForMassSelection(
1817
$accountListId: ID!
19-
$first: Int!
2018
$tasksFilter: TaskFilterSetInput
2119
) {
2220
tasks(
2321
accountListId: $accountListId
24-
first: $first
2522
tasksFilter: $tasksFilter
23+
first: 1000 # Maximum allowed by the API
2624
) {
2725
nodes {
2826
id

src/hooks/useMassSelection.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { renderHook } from '@testing-library/react';
22
import { ListHeaderCheckBoxState } from 'src/components/Shared/Header/ListHeader';
3-
import { useMassSelection } from './useMassSelection';
3+
import { UseMassSelectionResult, useMassSelection } from './useMassSelection';
44

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

@@ -117,4 +117,18 @@ describe('useMassSelection', () => {
117117
expect(result.current.ids).toEqual(['1', '2', '3', '7', '8', '9', '10']);
118118
});
119119
});
120+
121+
it('deselects removed ids', () => {
122+
const { result, rerender } = renderHook<
123+
UseMassSelectionResult,
124+
{ ids: string[] }
125+
>(({ ids }) => useMassSelection(ids), {
126+
initialProps: { ids: defaultIdsList },
127+
});
128+
129+
result.current.selectMultipleIds(['1', '2', '3']);
130+
131+
rerender({ ids: ['2', '3', '4'] });
132+
expect(result.current.ids).toEqual(['2', '3']);
133+
});
120134
});

0 commit comments

Comments
 (0)