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

Refactor custom unit rate update #10557

Merged
merged 38 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
607e5c5
add copy
jasperhuangg Aug 25, 2022
55af930
update setCustomUnitRate
jasperhuangg Aug 25, 2022
4cbb5d4
update setCustomUnitRate
jasperhuangg Aug 25, 2022
ec577cd
merge main
jasperhuangg Aug 29, 2022
065909a
WIP, online updates work, but need to figure out issue with data shap…
jasperhuangg Aug 29, 2022
e068def
merge main
jasperhuangg Aug 30, 2022
131144f
merge main
jasperhuangg Aug 30, 2022
5cff69a
remove unused
jasperhuangg Aug 30, 2022
d0b1393
remove unused
jasperhuangg Aug 30, 2022
ef76111
remove unused
jasperhuangg Aug 30, 2022
d2a0ea3
flatten customUnit rate array
jasperhuangg Aug 30, 2022
942416f
flatten customUnit rate array
jasperhuangg Aug 30, 2022
46eb7b5
fix linter error
jasperhuangg Aug 30, 2022
f2dbc32
update comment
jasperhuangg Aug 30, 2022
230cf42
revert unused
jasperhuangg Aug 30, 2022
7f7cadd
key by ID to get rates
jasperhuangg Aug 30, 2022
0ced3e5
access directly
jasperhuangg Aug 30, 2022
651ab0a
cleanup
jasperhuangg Aug 30, 2022
1e93077
cleanup
jasperhuangg Aug 30, 2022
c6a2304
fix propTypes
jasperhuangg Aug 30, 2022
71447ec
update customUnitRate accessing
jasperhuangg Aug 30, 2022
1da0a2a
remove unused
jasperhuangg Aug 30, 2022
55252de
cleanup
jasperhuangg Aug 30, 2022
b31f47b
Merge branch 'main' of github.com:Expensify/App into jasper-refactorP…
jasperhuangg Aug 30, 2022
ca7638e
Merge branch 'main' of github.com:Expensify/App into jasper-refactorP…
jasperhuangg Aug 31, 2022
4591cef
add comment
jasperhuangg Aug 31, 2022
f862e26
use update instead of set
jasperhuangg Aug 31, 2022
7aa9ab6
remove _.omit
jasperhuangg Aug 31, 2022
74ff01e
round to 3 decimal places before multiplying and passing to Policy ac…
jasperhuangg Aug 31, 2022
49f7118
remove defaults
jasperhuangg Aug 31, 2022
be512f5
use onyxRates instead of rates
jasperhuangg Aug 31, 2022
0c591d1
use onyxRates instead of rates
jasperhuangg Sep 1, 2022
8004b38
merge main
jasperhuangg Sep 5, 2022
39c5042
fix stuff messed up in merge
jasperhuangg Sep 5, 2022
dbaaa36
rename rateValue => unitRateValue
jasperhuangg Sep 5, 2022
c55d97b
fix stuff messed up in merge
jasperhuangg Sep 5, 2022
555a489
rename variables
jasperhuangg Sep 5, 2022
d3e4d63
Merge branch 'main' of github.com:Expensify/App into jasper-refactorP…
jasperhuangg Sep 6, 2022
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/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ const CONST = {
ADMIN: 'admin',
},
ROOM_PREFIX: '#',
CUSTOM_UNIT_RATE_BASE_OFFSET: 100,
},

CUSTOM_UNITS: {
Expand Down
4 changes: 4 additions & 0 deletions src/components/DotIndicatorMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const DotIndicatorMessage = (props) => {
.keys()
.sortBy()
.map(key => props.messages[key])

// Using uniq here since some fields are wrapped by the same OfflineWithFeedback component (e.g. WorkspaceReimburseView)
// and can potentially pass the same error.
.uniq()
.value();

return (
Expand Down
114 changes: 81 additions & 33 deletions src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -580,14 +580,21 @@ function setWorkspaceErrors(policyID, errors) {

/**
* @param {String} policyID
* @param {Number} customUnitID
* @param {String} customUnitID
* @param {String} customUnitRateID
*/
function removeUnitError(policyID, customUnitID) {
function clearCustomUnitErrors(policyID, customUnitID, customUnitRateID) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {
customUnits: {
[customUnitID]: {
errors: null,
pendingAction: null,
onyxRates: {
[customUnitRateID]: {
errors: null,
pendingAction: null,
},
},
},
},
});
Expand All @@ -603,17 +610,17 @@ function hideWorkspaceAlertMessage(policyID) {
/**
* @param {String} policyID
* @param {Object} currentCustomUnit
* @param {Object} values The new custom unit values
* @param {Object} newCustomUnit
*/
function updateWorkspaceCustomUnit(policyID, currentCustomUnit, values) {
function updateWorkspaceCustomUnit(policyID, currentCustomUnit, newCustomUnit) {
const optimisticData = [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[values.customUnitID]: {
...values,
[newCustomUnit.customUnitID]: {
...newCustomUnit,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
Expand All @@ -627,7 +634,7 @@ function updateWorkspaceCustomUnit(policyID, currentCustomUnit, values) {
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[values.customUnitID]: {
[newCustomUnit.customUnitID]: {
pendingAction: null,
errors: null,
},
Expand Down Expand Up @@ -657,40 +664,81 @@ function updateWorkspaceCustomUnit(policyID, currentCustomUnit, values) {

API.write('UpdateWorkspaceCustomUnit', {
policyID,
customUnit: JSON.stringify(values),
customUnit: JSON.stringify(newCustomUnit),
}, {optimisticData, successData, failureData});
}

/**
* @param {String} policyID
* @param {Object} currentCustomUnitRate
* @param {String} customUnitID
* @param {Object} values
* @param {Object} newCustomUnitRate
*/
function setCustomUnitRate(policyID, customUnitID, values) {
DeprecatedAPI.Policy_CustomUnitRate_Update({
policyID: policyID.toString(),
customUnitID: customUnitID.toString(),
customUnitRate: JSON.stringify(values),
lastModified: null,
})
.then((response) => {
if (response.jsonCode !== 200) {
throw new Error();
}
function updateCustomUnitRate(policyID, currentCustomUnitRate, customUnitID, newCustomUnitRate) {
const optimisticData = [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[customUnitID]: {
onyxRates: {
[newCustomUnitRate.customUnitRateID]: {
...newCustomUnitRate,
errors: null,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
},
},
},
];

const successData = [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[customUnitID]: {
onyxRates: {
[newCustomUnitRate.customUnitRateID]: {
pendingAction: null,
},
},
},
},
},
},
];

updateLocalPolicyValues(policyID, {
customUnit: {
rate: {
id: values.customUnitRateID,
name: values.name,
value: Number(values.rate),
const failureData = [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[customUnitID]: {
onyxRates: {
[currentCustomUnitRate.customUnitRateID]: {
...currentCustomUnitRate,
errors: {
[DateUtils.getMicroseconds()]: Localize.translateLocal('workspace.reimburse.updateCustomUnitError'),
},
},
},
},
},
});
}).catch(() => {
// Show the user feedback
Growl.error(Localize.translateLocal('workspace.editor.genericFailureMessage'), 5000);
});
},
},
];

API.write('UpdateWorkspaceCustomUnitRate', {
policyID,
customUnitID,
customUnitRate: JSON.stringify(newCustomUnitRate),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused a regression #26676. Previously the custom unit rate was simplified to only include relevant data that should be sent. Now we are sending the data from Onyx which may include client-only fields such as pendingAction and errors.

}, {optimisticData, successData, failureData});
}

/**
Expand Down Expand Up @@ -822,13 +870,13 @@ export {
create,
update,
setWorkspaceErrors,
removeUnitError,
clearCustomUnitErrors,
hideWorkspaceAlertMessage,
deletePolicy,
createAndNavigate,
createAndGetPolicyList,
updateWorkspaceCustomUnit,
setCustomUnitRate,
updateCustomUnitRate,
updateLastAccessedWorkspace,
subscribeToPolicyEvents,
clearDeleteMemberError,
Expand Down
46 changes: 25 additions & 21 deletions src/pages/workspace/reimburse/WorkspaceReimburseView.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const propTypes = {
attributes: PropTypes.shape({
unit: PropTypes.string,
}),
rates: PropTypes.arrayOf(
onyxRates: PropTypes.objectOf(
PropTypes.shape({
customUnitRateID: PropTypes.string,
name: PropTypes.string,
Expand All @@ -62,14 +62,14 @@ class WorkspaceReimburseView extends React.Component {
constructor(props) {
super(props);
const distanceCustomUnit = _.find(lodashGet(props, 'policy.customUnits', {}), unit => unit.name === 'Distance');
const customUnitRate = _.find(lodashGet(distanceCustomUnit, 'onyxRates', {}), rate => rate.name === 'Default Rate');

this.state = {
unitID: lodashGet(distanceCustomUnit, 'customUnitID', ''),
unitName: lodashGet(distanceCustomUnit, 'name', ''),
unitValue: lodashGet(distanceCustomUnit, 'attributes.unit', 'mi'),
rateID: lodashGet(distanceCustomUnit, 'rates[0].customUnitRateID', ''),
rateName: lodashGet(distanceCustomUnit, 'rates[0].name', ''),
rateValue: this.getRateDisplayValue(lodashGet(distanceCustomUnit, 'rates[0].rate', 0) / 100),
unitRateID: lodashGet(customUnitRate, 'customUnitRateID', ''),
unitRateValue: this.getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET),
outputCurrency: lodashGet(props, 'policy.outputCurrency', ''),
};

Expand Down Expand Up @@ -98,14 +98,13 @@ class WorkspaceReimburseView extends React.Component {
.values()
.findWhere({name: CONST.CUSTOM_UNITS.NAME_DISTANCE})
.value();

const customUnitRate = _.find(lodashGet(distanceCustomUnit, 'onyxRates', {}), rate => rate.name === 'Default Rate');
this.setState({
unitID: lodashGet(distanceCustomUnit, 'customUnitID', ''),
unitName: lodashGet(distanceCustomUnit, 'name', ''),
unitValue: lodashGet(distanceCustomUnit, 'attributes.unit', 'mi'),
rateID: lodashGet(distanceCustomUnit, 'rates[0].customUnitRateID', ''),
rateName: lodashGet(distanceCustomUnit, 'rates[0].name', ''),
rateValue: this.getRateDisplayValue(lodashGet(distanceCustomUnit, 'rates[0].rate', 0) / 100),
unitRateID: lodashGet(customUnitRate, 'customUnitRateID'),
unitRateValue: this.getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / 100),
});
}

Expand All @@ -130,10 +129,10 @@ class WorkspaceReimburseView extends React.Component {
const isInvalidRateValue = value !== '' && !CONST.REGEX.RATE_VALUE.test(value);

this.setState(prevState => ({
rateValue: !isInvalidRateValue ? value : prevState.rateValue,
unitRateValue: !isInvalidRateValue ? value : prevState.unitRateValue,
}), () => {
// Set the corrected value with a delay and sync to the server
this.updateRateValueDebounced(this.state.rateValue);
this.updateRateValueDebounced(this.state.unitRateValue);
});
}

Expand All @@ -156,7 +155,7 @@ class WorkspaceReimburseView extends React.Component {
return;
}

this.updateRateValueDebounced(this.state.rateValue);
this.updateRateValueDebounced(this.state.unitRateValue);
}

updateRateValue(value) {
Expand All @@ -167,14 +166,15 @@ class WorkspaceReimburseView extends React.Component {
}

this.setState({
rateValue: numValue.toFixed(3),
unitRateValue: numValue.toFixed(3),
});

Policy.setCustomUnitRate(this.props.policyID, this.state.unitID, {
customUnitRateID: this.state.rateID,
name: this.state.rateName,
rate: numValue.toFixed(3) * 100,
}, null);
const distanceCustomUnit = _.find(lodashGet(this.props, 'policy.customUnits', {}), unit => unit.name === 'Distance');
const currentCustomUnitRate = lodashGet(distanceCustomUnit, ['onyxRates', this.state.unitRateID], {});
Policy.updateCustomUnitRate(this.props.policyID, currentCustomUnitRate, this.state.unitID, {
...currentCustomUnitRate,
rate: numValue.toFixed(3) * CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET,
});
}

render() {
Expand Down Expand Up @@ -214,17 +214,21 @@ class WorkspaceReimburseView extends React.Component {
<Text>{this.props.translate('workspace.reimburse.trackDistanceCopy')}</Text>
</View>
<OfflineWithFeedback
errors={lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'errors'])}
pendingAction={lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'pendingAction'])}
onClose={() => Policy.removeUnitError(this.props.policyID, this.state.unitID)}
errors={{
...lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'errors'], {}),
...lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'onyxRates', this.state.unitRateID, 'errors'], {}),
}}
pendingAction={lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'pendingAction'])
|| lodashGet(this.props, ['policy', 'customUnits', this.state.unitID, 'onyxRates', this.state.unitRateID, 'pendingAction'])}
onClose={() => Policy.clearCustomUnitErrors(this.props.policyID, this.state.unitID, this.state.unitRateID)}
>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mv2]}>
<View style={[styles.rateCol]}>
<TextInput
label={this.props.translate('workspace.reimburse.trackDistanceRate')}
placeholder={this.state.outputCurrency}
onChangeText={value => this.setRate(value)}
value={this.state.rateValue}
value={this.state.unitRateValue}
autoCompleteType="off"
autoCorrect={false}
keyboardType={CONST.KEYBOARD_TYPE.DECIMAL_PAD}
Expand Down
Loading