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

Fix regression #38911

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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
8 changes: 4 additions & 4 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PODS:
- React-Core
- Expo (50.0.4):
- ExpoModulesCore
- ExpoImage (1.11.0):
- ExpoImage (1.10.1):
- ExpoModulesCore
- SDWebImage (~> 5.17.0)
- SDWebImageAVIFCoder (~> 0.10.1)
Expand Down Expand Up @@ -1790,7 +1790,7 @@ SPEC CHECKSUMS:
EXAV: 09a4d87fa6b113fbb0ada3aade6799f78271cb44
EXImageLoader: 55080616b2fe9da19ef8c7f706afd9814e279b6b
Expo: 1e3bcf9dd99de57a636127057f6b488f0609681a
ExpoImage: 390c524542b258f8173f475c1cc71f016444a7be
ExpoImage: 1cdaa65a6a70bb01067e21ad1347ff2d973885f5
ExpoImageManipulator: c1d7cb865eacd620a35659f3da34c70531f10b59
ExpoModulesCore: 96d1751929ad10622773bb729ab28a8423f0dd0c
FBLazyVector: fbc4957d9aa695250b55d879c1d86f79d7e69ab4
Expand Down Expand Up @@ -1921,8 +1921,8 @@ SPEC CHECKSUMS:
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2
VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a
Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047
Yoga: 13c8ef87792450193e117976337b8527b49e8c03

PODFILE CHECKSUM: a431c146e1501391834a2f299a74093bac53b530

COCOAPODS: 1.13.0
COCOAPODS: 1.15.2
38 changes: 3 additions & 35 deletions src/libs/actions/TransactionEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,8 @@ import type {OnyxEntry} from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Transaction} from '@src/types/onyx';

/**
* Makes a backup copy of a transaction object that can be restored when the user cancels editing a transaction.
*/
function createBackupTransaction(transaction: OnyxEntry<Transaction>) {
if (!transaction) {
return;
}

const newTransaction = {
...transaction,
};

// 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);
}

/**
* 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);
}

function restoreOriginalTransactionFromBackup(transactionID: string) {
const connectionID = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`,
callback: (backupTransaction) => {
Onyx.disconnect(connectionID);

// Use set to completely overwrite the original transaction
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, backupTransaction);
removeBackupTransaction(transactionID);
},
});
function restoreOriginalTransactionFromBackup(transactionID: string, backupTransaction: OnyxEntry<Transaction>) {
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, backupTransaction);
}

export {createBackupTransaction, removeBackupTransaction, restoreOriginalTransactionFromBackup};
export default {restoreOriginalTransactionFromBackup};
51 changes: 34 additions & 17 deletions src/pages/iou/request/step/IOURequestStepDistance.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import lodashGet from 'lodash/get';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import Button from '@components/Button';
import DistanceRequestFooter from '@components/DistanceRequest/DistanceRequestFooter';
Expand All @@ -22,8 +21,8 @@ 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';
import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes';
import StepScreenWrapper from './StepScreenWrapper';
Expand All @@ -40,15 +39,11 @@ const propTypes = {

/** The transaction object being modified in Onyx */
transaction: transactionPropTypes,

/** backup version of the original transaction */
transactionBackup: transactionPropTypes,
};

const defaultProps = {
report: {},
transaction: {},
transactionBackup: {},
};

function IOURequestStepDistance({
Expand All @@ -57,7 +52,6 @@ function IOURequestStepDistance({
params: {action, iouType, reportID, transactionID, backTo},
},
transaction,
transactionBackup,
}) {
const styles = useThemeStyles();
const {isOffline} = useNetwork();
Expand Down Expand Up @@ -85,6 +79,8 @@ function IOURequestStepDistance({
const atLeastTwoDifferentWaypointsError = useMemo(() => _.size(validatedWaypoints) < 2, [validatedWaypoints]);
const isEditing = action === CONST.IOU.ACTION.EDIT;
const isCreatingNewRequest = Navigation.getActiveRoute().includes('start');
const transactionWasSaved = useRef(false);
const [transactionBackup, setTransactionBackup] = useState({});

useEffect(() => {
MapboxToken.init();
Expand Down Expand Up @@ -112,6 +108,30 @@ function IOURequestStepDistance({
setShouldShowAtLeastTwoDifferentWaypointsError(false);
}, [atLeastTwoDifferentWaypointsError, duplicateWaypointsError, hasRouteError, isLoading, isLoadingRoute, nonEmptyWaypointsCount, transaction]);

useEffect(() => {
if (isCreatingNewRequest) {
return () => {};
}
// 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.

// On mount, create the backup transaction.
setTransactionBackup(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 || _.isEqual(transaction, transactionBackup)) {
return;
}
TransactionEdit.restoreOriginalTransactionFromBackup(lodashGet(transaction, 'transactionID', ''), transactionBackup);
setTransactionBackup({});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const navigateBack = () => {
Navigation.goBack(backTo);
};
Expand Down Expand Up @@ -187,10 +207,14 @@ function IOURequestStepDistance({

const submitWaypoints = useCallback(() => {
// If there is any error or loading state, don't let user go to next page.
if (duplicateWaypointsError || atLeastTwoDifferentWaypointsError || hasRouteError || isLoadingRoute || isLoading) {
if (duplicateWaypointsError || atLeastTwoDifferentWaypointsError || hasRouteError || isLoadingRoute || (!isEditing && isLoading)) {
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
Expand All @@ -213,6 +237,7 @@ function IOURequestStepDistance({
hasRouteError,
isLoadingRoute,
isLoading,
isCreatingNewRequest,
isEditing,
navigateToNextStep,
transactionBackup,
Expand Down Expand Up @@ -287,12 +312,4 @@ IOURequestStepDistance.displayName = 'IOURequestStepDistance';
IOURequestStepDistance.propTypes = propTypes;
IOURequestStepDistance.defaultProps = defaultProps;

export default compose(
withWritableReportOrNotFound,
withFullTransactionOrNotFound,
withOnyx({
transactionBackup: {
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${props.transactionID}`,
},
}),
)(IOURequestStepDistance);
export default compose(withWritableReportOrNotFound, withFullTransactionOrNotFound)(IOURequestStepDistance);
Loading