diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 2b3ae6da46ac..1eafd9d898ec 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -336,9 +336,10 @@ const ONYXKEYS = { SECURITY_GROUP: 'securityGroup_', TRANSACTION: 'transactions_', TRANSACTION_VIOLATIONS: 'transactionViolations_', + TRANSACTION_DRAFT: 'transactionsDraft_', // Holds temporary transactions used during the creation and edit flow - TRANSACTION_DRAFT: 'transactionsDraft_', + TRANSACTION_BACKUP: 'transactionsBackup_', SPLIT_TRANSACTION_DRAFT: 'splitTransactionDraft_', PRIVATE_NOTES_DRAFT: 'privateNotesDraft_', NEXT_STEP: 'reportNextStep_', @@ -538,6 +539,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup; [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction; + [ONYXKEYS.COLLECTION.TRANSACTION_BACKUP]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; diff --git a/src/libs/actions/TransactionEdit.ts b/src/libs/actions/TransactionEdit.ts index b1710aa72cbb..26219d72920e 100644 --- a/src/libs/actions/TransactionEdit.ts +++ b/src/libs/actions/TransactionEdit.ts @@ -16,24 +16,24 @@ function createBackupTransaction(transaction: OnyxEntry) { }; // Use set so that it will always fully overwrite any backup transaction that could have existed before - Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transaction.transactionID}`, newTransaction); + Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transaction.transactionID}`, newTransaction); } /** * Removes a transaction from Onyx that was only used temporary in the edit flow */ function removeBackupTransaction(transactionID: string) { - Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, null); + Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transactionID}`, null); } -function restoreOriginalTransactionFromBackup(transactionID: string) { +function restoreOriginalTransactionFromBackup(transactionID: string, isDraft: boolean) { const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transactionID}`, callback: (backupTransaction) => { Onyx.disconnect(connectionID); // Use set to completely overwrite the original transaction - Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, backupTransaction); + Onyx.set(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, backupTransaction); removeBackupTransaction(transactionID); }, }); diff --git a/src/pages/iou/request/step/IOURequestStepDistance.js b/src/pages/iou/request/step/IOURequestStepDistance.js index 145bd6ff6e33..398b2f83712b 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.js +++ b/src/pages/iou/request/step/IOURequestStepDistance.js @@ -22,6 +22,7 @@ import variables from '@styles/variables'; import * as IOU from '@userActions/IOU'; import * as MapboxToken from '@userActions/MapboxToken'; import * as Transaction from '@userActions/Transaction'; +import * as TransactionEdit from '@userActions/TransactionEdit'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -84,6 +85,7 @@ function IOURequestStepDistance({ const duplicateWaypointsError = useMemo(() => nonEmptyWaypointsCount >= 2 && _.size(validatedWaypoints) !== nonEmptyWaypointsCount, [nonEmptyWaypointsCount, validatedWaypoints]); const atLeastTwoDifferentWaypointsError = useMemo(() => _.size(validatedWaypoints) < 2, [validatedWaypoints]); const isEditing = action === CONST.IOU.ACTION.EDIT; + const transactionWasSaved = useRef(false); const isCreatingNewRequest = !(backTo || isEditing); useEffect(() => { @@ -112,6 +114,29 @@ function IOURequestStepDistance({ setShouldShowAtLeastTwoDifferentWaypointsError(false); }, [atLeastTwoDifferentWaypointsError, duplicateWaypointsError, hasRouteError, isLoading, isLoadingRoute, nonEmptyWaypointsCount, transaction]); + // This effect runs when the component is mounted and unmounted. It's purpose is to be able to properly + // discard changes if the user cancels out of making any changes. This is accomplished by backing up the + // original transaction, letting the user modify the current transaction, and then if the user ever + // cancels out of the modal without saving changes, the original transaction is restored from the backup. + useEffect(() => { + if (isCreatingNewRequest) { + return () => {}; + } + + // On mount, create the backup transaction. + TransactionEdit.createBackupTransaction(transaction); + + return () => { + // If the user cancels out of the modal without without saving changes, then the original transaction + // needs to be restored from the backup so that all changes are removed. + if (transactionWasSaved.current) { + return; + } + TransactionEdit.restoreOriginalTransactionFromBackup(lodashGet(transaction, 'transactionID', ''), action === CONST.IOU.ACTION.CREATE); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const navigateBack = () => { Navigation.goBack(backTo); }; @@ -191,6 +216,9 @@ function IOURequestStepDistance({ setShouldShowAtLeastTwoDifferentWaypointsError(true); return; } + if (!isCreatingNewRequest) { + transactionWasSaved.current = true; + } if (isEditing) { // If nothing was changed, simply go to transaction thread // We compare only addresses because numbers are rounded while backup @@ -213,6 +241,7 @@ function IOURequestStepDistance({ hasRouteError, isLoadingRoute, isLoading, + isCreatingNewRequest, isEditing, navigateToNextStep, transactionBackup, @@ -292,7 +321,10 @@ export default compose( withFullTransactionOrNotFound, withOnyx({ transactionBackup: { - key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${props.transactionID}`, + key: ({route}) => { + const transactionID = lodashGet(route, 'params.transactionID', 0); + return `${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transactionID}`; + }, }, }), )(IOURequestStepDistance);