Skip to content

Commit 404171d

Browse files
authored
Merge pull request Expensify#89967 from Expensify/valforte/fixGreyedAccountManagerChat
Handle report duplication so opening Relationship Manager chat works properly
2 parents 1e83f0b + 02f0523 commit 404171d

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

src/libs/actions/RequestConflictUtils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,23 @@ function resolveOpenReportDuplicationConflictAction<TKey extends OnyxKey>(persis
8585
};
8686
}
8787

88+
// The queued request carries the participants needed to create the optimistic chat on the
89+
// server (e.g. from navigateToAndOpenReportWithAccountIDs). A follow-up OpenReport fired by
90+
// ReportFetchHandler when the screen mounts has no participants. Replacing would drop the
91+
// accountIDList, leaving the server with no way to resolve the optimistic reportID — Auth
92+
// returns NIL reportSummary and PHP throws "Report not found" (da7984df).
93+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
94+
const queuedHasParticipants = !!(request.data?.emailList || request.data?.accountIDList);
95+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
96+
const newHasParticipants = !!(parameters.emailList || parameters.accountIDList);
97+
if (queuedHasParticipants && !newHasParticipants) {
98+
return {
99+
conflictAction: {
100+
type: 'noAction',
101+
},
102+
};
103+
}
104+
88105
// In other cases it's safe to replace the previous request with the new one
89106
return {
90107
conflictAction: {

tests/unit/RequestConflictUtilsTest.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
resolveDuplicationConflictAction,
77
resolveEditCommentWithNewAddCommentRequest,
88
resolveEnableFeatureConflicts,
9+
resolveOpenReportDuplicationConflictAction,
910
} from '@libs/actions/RequestConflictUtils';
1011
import {WRITE_COMMANDS} from '@libs/API/types';
1112
import type {WriteCommand} from '@libs/API/types';
@@ -163,6 +164,44 @@ describe('RequestConflictUtils', () => {
163164
});
164165
});
165166

167+
describe('resolveOpenReportDuplicationConflictAction', () => {
168+
it('returns push when no matching OpenReport for the reportID exists in the queue', () => {
169+
const persistedRequests = [{command: 'OpenApp'}, {command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '2'}}];
170+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1'} as never);
171+
expect(result).toEqual({conflictAction: {type: 'push'}});
172+
});
173+
174+
it('returns noAction when the queued OpenReport carries guidedSetupData', () => {
175+
const persistedRequests = [{command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '1', guidedSetupData: '[{}]'}}];
176+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1'} as never);
177+
expect(result).toEqual({conflictAction: {type: 'noAction'}});
178+
});
179+
180+
it('returns noAction when the queued request carries accountIDList but the new one has no participants', () => {
181+
const persistedRequests = [{command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '1', accountIDList: '10,20'}}];
182+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1'} as never);
183+
expect(result).toEqual({conflictAction: {type: 'noAction'}});
184+
});
185+
186+
it('replaces when the new request also carries an accountIDList', () => {
187+
const persistedRequests = [{command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '1', accountIDList: '10,20'}}];
188+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1', accountIDList: '10,20'} as never);
189+
expect(result).toEqual({conflictAction: {type: 'replace', index: 0}});
190+
});
191+
192+
it('replaces when neither queued nor new request has participants', () => {
193+
const persistedRequests = [{command: 'OpenApp'}, {command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '1'}}];
194+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1'} as never);
195+
expect(result).toEqual({conflictAction: {type: 'replace', index: 1}});
196+
});
197+
198+
it('replaces when the queued request has no participants but the new request does', () => {
199+
const persistedRequests = [{command: WRITE_COMMANDS.OPEN_REPORT, data: {reportID: '1'}}];
200+
const result = resolveOpenReportDuplicationConflictAction(persistedRequests, {reportID: '1', accountIDList: '10,20'} as never);
201+
expect(result).toEqual({conflictAction: {type: 'replace', index: 0}});
202+
});
203+
});
204+
166205
describe('resolveDetachReceiptConflicts', () => {
167206
it('returns push when no replace-receipt requests match transactionID', () => {
168207
const persistedRequests = [{command: 'OpenReport'}, {command: WRITE_COMMANDS.REPLACE_RECEIPT, data: {transactionID: '2'}}, {command: 'CloseAccount'}];

0 commit comments

Comments
 (0)