Skip to content

Commit

Permalink
Merge pull request #10692 from Expensify/yuwen-workspaceReimbursePage
Browse files Browse the repository at this point in the history
Refactor of WorkspaceReimburseView to use new API
  • Loading branch information
arosiclair authored Sep 1, 2022
2 parents 4e5c08b + 48f2147 commit ffa839e
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 106 deletions.
4 changes: 4 additions & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@ const CONST = {
ROOM_PREFIX: '#',
},

CUSTOM_UNITS: {
NAME_DISTANCE: 'Distance',
},

TERMS: {
CFPB_PREPAID: 'cfpb.gov/prepaid',
CFPB_COMPLAINT: 'cfpb.gov/complaint',
Expand Down
5 changes: 5 additions & 0 deletions src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,10 @@ function generatePolicyID() {
return _.times(16, () => Math.floor(Math.random() * 16).toString(16)).join('').toUpperCase();
}

function openWorkspaceReimburseView(policyID) {
API.read('OpenWorkspaceReimburseView', {policyID});
}

export {
getPolicyList,
loadFullPolicy,
Expand All @@ -822,6 +826,7 @@ export {
subscribeToPolicyEvents,
clearDeleteMemberError,
clearAddMemberError,
openWorkspaceReimburseView,
generateDefaultWorkspaceName,
updateGeneralSettings,
clearWorkspaceGeneralSettingsErrors,
Expand Down
235 changes: 129 additions & 106 deletions src/pages/workspace/reimburse/WorkspaceReimburseView.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import * as Policy from '../../../libs/actions/Policy';
import withFullPolicy from '../withFullPolicy';
import CONST from '../../../CONST';
import Button from '../../../components/Button';
import {withNetwork} from '../../../components/OnyxProvider';
import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
import * as ReimbursementAccount from '../../../libs/actions/ReimbursementAccount';
import networkPropTypes from '../../../components/networkPropTypes';

const propTypes = {
/** The policy ID currently being configured */
policyID: PropTypes.string.isRequired,

/** Does the user have a VBA in their account? */
hasVBA: PropTypes.bool.isRequired,

/** Policy values needed in the component */
policy: PropTypes.shape({
customUnits: PropTypes.objectOf(
Expand All @@ -49,8 +49,12 @@ const propTypes = {
}),
),
outputCurrency: PropTypes.string,
hasVBA: PropTypes.bool,
}).isRequired,

/** Information about the network */
network: networkPropTypes.isRequired,

...withLocalizePropTypes,
};

Expand Down Expand Up @@ -84,6 +88,35 @@ class WorkspaceReimburseView extends React.Component {
this.updateRateValueDebounced = _.debounce(this.updateRateValue.bind(this), 1000);
}

componentDidMount() {
Policy.openWorkspaceReimburseView(this.props.policyID);
}

componentDidUpdate(prevProps) {
if (prevProps.policy.customUnits !== this.props.policy.customUnits) {
const distanceCustomUnit = _.chain(lodashGet(this.props, 'policy.customUnits', []))
.values()
.findWhere({name: CONST.CUSTOM_UNITS.NAME_DISTANCE})
.value();

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

const reconnecting = prevProps.network.isOffline && !this.props.network.isOffline;
if (!reconnecting) {
return;
}

Policy.openWorkspaceReimburseView(this.props.policyID);
}

getRateDisplayValue(value) {
const numValue = parseFloat(value);
if (Number.isNaN(numValue)) {
Expand All @@ -104,19 +137,6 @@ class WorkspaceReimburseView extends React.Component {
});
}

static getDerivedStateFromProps(props, state) {
const distanceCustomUnit = _.find(lodashGet(props, 'policy.customUnits', {}), unit => unit.name === 'Distance');
const unitValue = lodashGet(distanceCustomUnit, 'attributes.unit', 'mi');

if (unitValue !== state.unitValue) {
return {
unitValue,
};
}

return null;
}

setUnit(value) {
if (value === this.state.unitValue) {
return;
Expand Down Expand Up @@ -160,107 +180,109 @@ class WorkspaceReimburseView extends React.Component {
render() {
return (
<>
<Section
title={this.props.translate('workspace.reimburse.captureReceipts')}
icon={Illustrations.ReceiptYellow}
menuItems={[
{
title: this.props.translate('workspace.reimburse.viewAllReceipts'),
onPress: () => Link.openOldDotLink(`expenses?policyIDList=${this.props.policyID}&billableReimbursable=reimbursable&submitterEmail=%2B%2B`),
icon: Expensicons.Receipt,
shouldShowRightIcon: true,
iconRight: Expensicons.NewWindow,
},
]}
>
<View style={[styles.mv4, styles.flexRow, styles.flexWrap]}>
<Text>
{this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')}
<CopyTextToClipboard
text="receipts@expensify.com"
textStyles={[styles.textBlue]}
/>
<Text>{this.props.translate('workspace.reimburse.captureNoVBACopyAfterEmail')}</Text>
</Text>
</View>
</Section>

<Section
title={this.props.translate('workspace.reimburse.trackDistance')}
icon={Illustrations.GpsTrackOrange}
>
<View style={[styles.mv4]}>
<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)}
>
<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}
autoCompleteType="off"
autoCorrect={false}
keyboardType={CONST.KEYBOARD_TYPE.DECIMAL_PAD}
onKeyPress={this.debounceUpdateOnCursorMove}
/>
</View>
<View style={[styles.unitCol]}>
<Picker
label={this.props.translate('workspace.reimburse.trackDistanceUnit')}
items={this.unitItems}
value={this.state.unitValue}
onInputChange={value => this.setUnit(value)}
/>
</View>
</View>
</OfflineWithFeedback>
</Section>

{!this.props.hasVBA && (
<FullPageNotFoundView shouldShow={_.isEmpty(this.props.policy)}>
<Section
title={this.props.translate('workspace.reimburse.unlockNextDayReimbursements')}
icon={Illustrations.JewelBoxGreen}
>
<View style={[styles.mv4]}>
<Text>{this.props.translate('workspace.reimburse.unlockNoVBACopy')}</Text>
</View>
<Button
text={this.props.translate('workspace.common.bankAccount')}
onPress={() => ReimbursementAccount.navigateToBankAccountRoute(this.props.policyID)}
icon={Expensicons.Bank}
style={[styles.mt4]}
iconStyles={[styles.buttonCTAIcon]}
shouldShowRightIcon
large
success
/>
</Section>
)}
{this.props.hasVBA && (
<Section
title={this.props.translate('workspace.reimburse.fastReimbursementsHappyMembers')}
icon={Illustrations.BankUserGreen}
title={this.props.translate('workspace.reimburse.captureReceipts')}
icon={Illustrations.ReceiptYellow}
menuItems={[
{
title: this.props.translate('workspace.reimburse.reimburseReceipts'),
onPress: () => Link.openOldDotLink(`reports?policyID=${this.props.policyID}&from=all&type=expense&showStates=Archived&isAdvancedFilterMode=true`),
icon: Expensicons.Bank,
title: this.props.translate('workspace.reimburse.viewAllReceipts'),
onPress: () => Link.openOldDotLink(`expenses?policyIDList=${this.props.policyID}&billableReimbursable=reimbursable&submitterEmail=%2B%2B`),
icon: Expensicons.Receipt,
shouldShowRightIcon: true,
iconRight: Expensicons.NewWindow,
},
]}
>
<View style={[styles.mv4, styles.flexRow, styles.flexWrap]}>
<Text>
{this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')}
<CopyTextToClipboard
text="receipts@expensify.com"
textStyles={[styles.textBlue]}
/>
<Text>{this.props.translate('workspace.reimburse.captureNoVBACopyAfterEmail')}</Text>
</Text>
</View>
</Section>

<Section
title={this.props.translate('workspace.reimburse.trackDistance')}
icon={Illustrations.GpsTrackOrange}
>
<View style={[styles.mv4]}>
<Text>{this.props.translate('workspace.reimburse.fastReimbursementsVBACopy')}</Text>
<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)}
>
<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}
autoCompleteType="off"
autoCorrect={false}
keyboardType={CONST.KEYBOARD_TYPE.DECIMAL_PAD}
onKeyPress={this.debounceUpdateOnCursorMove}
/>
</View>
<View style={[styles.unitCol]}>
<Picker
label={this.props.translate('workspace.reimburse.trackDistanceUnit')}
items={this.unitItems}
value={this.state.unitValue}
onInputChange={value => this.setUnit(value)}
/>
</View>
</View>
</OfflineWithFeedback>
</Section>
)}

{!this.props.hasVBA && (
<Section
title={this.props.translate('workspace.reimburse.unlockNextDayReimbursements')}
icon={Illustrations.JewelBoxGreen}
>
<View style={[styles.mv4]}>
<Text>{this.props.translate('workspace.reimburse.unlockNoVBACopy')}</Text>
</View>
<Button
text={this.props.translate('workspace.common.bankAccount')}
onPress={() => ReimbursementAccount.navigateToBankAccountRoute(this.props.policyID)}
icon={Expensicons.Bank}
style={[styles.mt4]}
iconStyles={[styles.buttonCTAIcon]}
shouldShowRightIcon
large
success
/>
</Section>
)}
{this.props.hasVBA && (
<Section
title={this.props.translate('workspace.reimburse.fastReimbursementsHappyMembers')}
icon={Illustrations.BankUserGreen}
menuItems={[
{
title: this.props.translate('workspace.reimburse.reimburseReceipts'),
onPress: () => Link.openOldDotLink(`reports?policyID=${this.props.policyID}&from=all&type=expense&showStates=Archived&isAdvancedFilterMode=true`),
icon: Expensicons.Bank,
shouldShowRightIcon: true,
iconRight: Expensicons.NewWindow,
},
]}
>
<View style={[styles.mv4]}>
<Text>{this.props.translate('workspace.reimburse.fastReimbursementsVBACopy')}</Text>
</View>
</Section>
)}
</FullPageNotFoundView>
</>
);
}
Expand All @@ -272,6 +294,7 @@ WorkspaceReimburseView.displayName = 'WorkspaceReimburseView';
export default compose(
withFullPolicy,
withLocalize,
withNetwork(),
withOnyx({
policy: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
Expand Down

0 comments on commit ffa839e

Please sign in to comment.