-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
EditRequestDistancePage.js
145 lines (127 loc) · 5.81 KB
/
EditRequestDistancePage.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useEffect, useRef} from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import DistanceRequest from '@components/DistanceRequest';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import transactionPropTypes from '@components/transactionPropTypes';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import usePrevious from '@hooks/usePrevious';
import Navigation from '@libs/Navigation/Navigation';
import * as IOU from '@userActions/IOU';
import * as TransactionEdit from '@userActions/TransactionEdit';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import reportPropTypes from './reportPropTypes';
const propTypes = {
/** The transactionID we're currently editing */
transactionID: PropTypes.string.isRequired,
/** The report to with which the distance request is associated */
report: reportPropTypes.isRequired,
/** Passed from the navigator */
route: PropTypes.shape({
/** Parameters the route gets */
params: PropTypes.shape({
/** Type of IOU */
iouType: PropTypes.oneOf(_.values(CONST.IOU.TYPE)),
/** Id of the report on which the distance request is being created */
reportID: PropTypes.string,
}),
}).isRequired,
/* Onyx props */
/** The original transaction that is being edited */
transaction: transactionPropTypes,
/** backup version of the original transaction */
transactionBackup: transactionPropTypes,
};
const defaultProps = {
transaction: {},
transactionBackup: {},
};
function EditRequestDistancePage({report, route, transaction, transactionBackup}) {
const {isOffline} = useNetwork();
const {translate} = useLocalize();
const transactionWasSaved = useRef(false);
const hasWaypointError = useRef(false);
const prevIsLoading = usePrevious(transaction.isLoading);
useEffect(() => {
hasWaypointError.current = Boolean(lodashGet(transaction, 'errorFields.route') || lodashGet(transaction, 'errorFields.waypoints'));
// When the loading goes from true to false, then we know the transaction has just been
// saved to the server. Check for errors. If there are no errors, then the modal can be closed.
if (prevIsLoading && !transaction.isLoading && !hasWaypointError.current) {
Navigation.dismissModal(report.reportID);
}
}, [transaction, prevIsLoading, report]);
useEffect(() => {
// 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.
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(transaction.transactionID);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
/**
* Save the changes to the original transaction object
* @param {Object} waypoints
*/
const saveTransaction = (waypoints) => {
// If nothing was changed, simply go to transaction thread
// We compare only addresses because numbers are rounded while backup
const oldWaypoints = lodashGet(transactionBackup, 'comment.waypoints', {});
const oldAddresses = _.mapObject(oldWaypoints, (waypoint) => _.pick(waypoint, 'address'));
const addresses = _.mapObject(waypoints, (waypoint) => _.pick(waypoint, 'address'));
if (_.isEqual(oldAddresses, addresses)) {
Navigation.dismissModal(report.reportID);
return;
}
transactionWasSaved.current = true;
IOU.updateDistanceRequest(transaction.transactionID, report.reportID, {waypoints});
// If the client is offline, then the modal can be closed as well (because there are no errors or other feedback to show them
// until they come online again and sync with the server).
if (isOffline) {
Navigation.dismissModal(report.reportID);
}
};
return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
shouldEnableMaxHeight
testID={EditRequestDistancePage.displayName}
>
<HeaderWithBackButton
title={translate('common.distance')}
onBackButtonPress={() => Navigation.goBack()}
/>
<DistanceRequest
report={report}
route={route}
transactionID={transaction.transactionID}
onSubmit={saveTransaction}
isEditingRequest
/>
</ScreenWrapper>
);
}
EditRequestDistancePage.propTypes = propTypes;
EditRequestDistancePage.defaultProps = defaultProps;
EditRequestDistancePage.displayName = 'EditRequestDistancePage';
export default withOnyx({
transaction: {
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}`,
},
transactionBackup: {
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}-backup`,
},
})(EditRequestDistancePage);