Skip to content
Draft
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
1 change: 1 addition & 0 deletions src/components/DotIndicatorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ function DotIndicatorMessage({messages = {}, style, type, textStyles, dismissErr
prompt: translate('common.genericErrorMessage'),
confirmText: translate('common.ok'),
shouldShowCancelButton: false,
shouldHandleNavigationBack: false,
});
});
} else if (href.endsWith('download')) {
Expand Down
33 changes: 29 additions & 4 deletions src/libs/ReceiptUploadRetryHandler/handleFileRetry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as IOU from '@userActions/IOU';
import {startSplitBill} from '@userActions/IOU/Split';
import {clearError} from '@userActions/Transaction';
import CONST from '@src/CONST';
import type Transaction from '@src/types/onyx/Transaction';
import type {ReceiptError} from '@src/types/onyx/Transaction';

export default function handleFileRetry(message: ReceiptError, file: File, dismissError: () => void, setShouldShowErrorModal: (value: boolean) => void) {
Expand All @@ -9,37 +11,60 @@ export default function handleFileRetry(message: ReceiptError, file: File, dismi
? (JSON.parse(message.retryParams) as IOU.ReplaceReceipt | IOU.StartSplitBilActionParams | IOU.CreateTrackExpenseParams | IOU.RequestMoneyInformation)
: message.retryParams;

// Use non-destructive error clearing when transactionID is available.
// The full dismissError() triggers cleanUpMoneyRequest() for pending ADD transactions,
// which deletes the transaction/report and navigates away before the retry can complete.
const clearReceiptError = () => {
if (message.transactionID) {
clearError(message.transactionID);
} else {
dismissError();
}
};

switch (message.action) {
case CONST.IOU.ACTION_PARAMS.REPLACE_RECEIPT: {
dismissError();
clearReceiptError();
const replaceReceiptParams = {...retryParams} as IOU.ReplaceReceipt;
replaceReceiptParams.file = file;
IOU.replaceReceipt(replaceReceiptParams);
break;
}
case CONST.IOU.ACTION_PARAMS.START_SPLIT_BILL: {
dismissError();
clearReceiptError();
const startSplitBillParams = {...retryParams} as IOU.StartSplitBilActionParams;
startSplitBillParams.receipt = file;
startSplitBillParams.shouldPlaySound = false;
startSplitBill(startSplitBillParams);
break;
}
case CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE: {
dismissError();
clearReceiptError();
const trackExpenseParams = {...retryParams} as IOU.CreateTrackExpenseParams;
trackExpenseParams.transactionParams.receipt = file;
trackExpenseParams.isRetry = true;
trackExpenseParams.shouldPlaySound = false;
trackExpenseParams.shouldHandleNavigation = false;
// Reuse the existing transaction so retry errors appear on the same
// transaction the user is viewing instead of creating a new one.
if (message.transactionID) {
trackExpenseParams.existingTransaction = {transactionID: message.transactionID} as Transaction;
}
IOU.trackExpense(trackExpenseParams);
break;
}
case CONST.IOU.ACTION_PARAMS.MONEY_REQUEST: {
dismissError();
clearReceiptError();
const requestMoneyParams = {...retryParams} as IOU.RequestMoneyInformation;
requestMoneyParams.transactionParams.receipt = file;
requestMoneyParams.isRetry = true;
requestMoneyParams.shouldPlaySound = false;
requestMoneyParams.shouldHandleNavigation = false;
// Reuse the existing transaction so retry errors appear on the same
// transaction the user is viewing instead of creating a new one.
if (message.transactionID) {
requestMoneyParams.existingTransactionDraft = {transactionID: message.transactionID} as Transaction;
}
IOU.requestMoney(requestMoneyParams);
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/IOU/Duplicate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ function duplicateExpenseTransaction({
iouRequestType: getRequestType(transaction),
modifiedCreated: '',
reportID: '1',
transactionID: '1',
transactionID: NumberUtils.rand64(),
},
transactionParams: {
...(params.transactionParams ?? {}),
Expand Down Expand Up @@ -652,7 +652,7 @@ function duplicateExpenseTransaction({
iouRequestType: getRequestType(transaction),
modifiedCreated: '',
reportID: '1',
transactionID: '1',
transactionID: NumberUtils.rand64(),
},
transactionParams: {
...(params.transactionParams ?? {}),
Expand Down
76 changes: 67 additions & 9 deletions src/libs/actions/IOU/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@
};

let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({

Check warning on line 774 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand Down Expand Up @@ -871,7 +871,7 @@

let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION,

Check warning on line 874 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
if (!value) {
Expand All @@ -885,7 +885,7 @@

let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,

Check warning on line 888 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
allTransactionDrafts = value ?? {};
Expand All @@ -894,7 +894,7 @@

let allTransactionViolations: NonNullable<OnyxCollection<OnyxTypes.TransactionViolations>> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,

Check warning on line 897 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
if (!value) {
Expand All @@ -908,7 +908,7 @@

let allPolicyTags: OnyxCollection<OnyxTypes.PolicyTagLists> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_TAGS,

Check warning on line 911 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
if (!value) {
Expand All @@ -921,7 +921,7 @@

let allReports: OnyxCollection<OnyxTypes.Report>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,

Check warning on line 924 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
allReports = value;
Expand All @@ -930,7 +930,7 @@

let allReportNameValuePairs: OnyxCollection<OnyxTypes.ReportNameValuePairs>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS,

Check warning on line 933 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (value) => {
allReportNameValuePairs = value;
Expand All @@ -940,7 +940,7 @@
let userAccountID = -1;
let currentUserEmail = '';
Onyx.connect({
key: ONYXKEYS.SESSION,

Check warning on line 943 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
callback: (value) => {
currentUserEmail = value?.email ?? '';
userAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID;
Expand All @@ -949,7 +949,7 @@

let deprecatedCurrentUserPersonalDetails: OnyxEntry<OnyxTypes.PersonalDetails>;
Onyx.connect({
key: ONYXKEYS.PERSONAL_DETAILS_LIST,

Check warning on line 952 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
callback: (value) => {
deprecatedCurrentUserPersonalDetails = value?.[userAccountID] ?? undefined;
},
Expand All @@ -957,7 +957,7 @@

let allReportActions: OnyxCollection<OnyxTypes.ReportActions>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,

Check warning on line 960 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
waitForCollectionCallback: true,
callback: (actions) => {
if (!actions) {
Expand Down Expand Up @@ -1748,6 +1748,7 @@
errorKey?: number,
action?: IOUActionParams,
retryParams?: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt,
transactionID?: string,
): Errors | ErrorFields {
const formattedRetryParams = typeof retryParams === 'string' ? retryParams : JSON.stringify(retryParams);

Expand All @@ -1760,6 +1761,7 @@
filename: filename ?? '',
action: action ?? '',
retryParams: formattedRetryParams,
...(transactionID && {transactionID}),
},
errorKey,
);
Expand Down Expand Up @@ -2394,7 +2396,15 @@
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`,
value: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, errorKey, CONST.IOU.ACTION_PARAMS.MONEY_REQUEST, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
errorKey,
CONST.IOU.ACTION_PARAMS.MONEY_REQUEST,
retryParams,
transaction.transactionID,
),
pendingFields: clearedPendingFields,
},
},
Expand All @@ -2405,15 +2415,31 @@
...(shouldCreateNewMoneyRequestReport
? {
[iou.createdAction.reportActionID]: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, errorKey, CONST.IOU.ACTION_PARAMS.MONEY_REQUEST, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
errorKey,
CONST.IOU.ACTION_PARAMS.MONEY_REQUEST,
retryParams,
transaction.transactionID,
),
},
[iou.action.reportActionID]: {
errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'),
},
}
: {
[iou.action.reportActionID]: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, errorKey, CONST.IOU.ACTION_PARAMS.MONEY_REQUEST, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
errorKey,
CONST.IOU.ACTION_PARAMS.MONEY_REQUEST,
retryParams,
transaction.transactionID,
),
},
}),
},
Expand Down Expand Up @@ -2898,15 +2924,31 @@
...(shouldCreateNewMoneyRequestReport
? {
[iouCreatedAction.reportActionID]: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, undefined, CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
undefined,
CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE,
retryParams,
transaction.transactionID,
),
},
[iouAction.reportActionID]: {
errors: getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'),
},
}
: {
[iouAction.reportActionID]: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, undefined, CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
undefined,
CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE,
retryParams,
transaction.transactionID,
),
},
}),
},
Expand All @@ -2918,7 +2960,15 @@
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
value: {
[iouAction.reportActionID]: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, undefined, CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
undefined,
CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE,
retryParams,
transaction.transactionID,
),
},
},
});
Expand Down Expand Up @@ -2950,7 +3000,15 @@
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`,
value: {
errors: getReceiptError(transaction.receipt, transaction.receipt?.filename, isScanRequest, undefined, CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE, retryParams),
errors: getReceiptError(
transaction.receipt,
transaction.receipt?.filename,
isScanRequest,
undefined,
CONST.IOU.ACTION_PARAMS.TRACK_EXPENSE,
retryParams,
transaction.transactionID,
),
pendingFields: clearedPendingFields,
},
},
Expand Down Expand Up @@ -6723,7 +6781,7 @@
existingTransactionID:
isMovingTransactionFromTrackExpense && linkedTrackedExpenseReportAction && isMoneyRequestAction(linkedTrackedExpenseReportAction)
? getOriginalMessage(linkedTrackedExpenseReportAction)?.IOUTransactionID
: undefined,
: existingTransaction?.transactionID,
participantParams: {
participant,
payeeAccountID,
Expand Down Expand Up @@ -11563,7 +11621,7 @@
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
value: {
receipt: !isEmptyObject(oldReceipt) ? oldReceipt : null,
errors: getReceiptError(receiptOptimistic, file.name, undefined, undefined, CONST.IOU.ACTION_PARAMS.REPLACE_RECEIPT, retryParams),
errors: getReceiptError(receiptOptimistic, file.name, undefined, undefined, CONST.IOU.ACTION_PARAMS.REPLACE_RECEIPT, retryParams, transactionID),
pendingFields: {
receipt: null,
},
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ type ReceiptError = {
/** Parameters required to retry the failed action */
retryParams: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt;

/** Transaction ID associated with the receipt error, used for non-destructive retry */
transactionID?: string;

/** The type of receipt error */
error: typeof CONST.IOU.RECEIPT_ERROR;
};
Expand Down
Loading