Skip to content

Commit

Permalink
Merge pull request #10861 from Expensify/OSBotify-cherry-pick-staging…
Browse files Browse the repository at this point in the history
…-10557

🍒 Cherry pick PR #10557 to staging 🍒
  • Loading branch information
OSBotify authored Sep 7, 2022
2 parents 713ec7f + 367b662 commit 24b3b27
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 61 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001019704
versionName "1.1.97-4"
versionCode 1001019703
versionName "1.1.97-3"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()

if (isNewArchitectureEnabled()) {
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.1.97.4</string>
<string>1.1.97.3</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.1.97.4</string>
<string>1.1.97.3</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.1.97-4",
"version": "1.1.97-3",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
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),
}, {optimisticData, successData, failureData});
}

/**
Expand Down Expand Up @@ -815,13 +863,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

0 comments on commit 24b3b27

Please sign in to comment.