diff --git a/src/pages/workspace/reimburse/WorkspaceReimburseView.js b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
index 9005374826b3..d30bb45bdb31 100644
--- a/src/pages/workspace/reimburse/WorkspaceReimburseView.js
+++ b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState, useEffect, useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
@@ -19,6 +19,7 @@ import * as Policy from '../../../libs/actions/Policy';
import CONST from '../../../CONST';
import ROUTES from '../../../ROUTES';
import ONYXKEYS from '../../../ONYXKEYS';
+import usePrevious from '../../../hooks/usePrevious';
import * as ReimbursementAccountProps from '../../ReimbursementAccount/reimbursementAccountPropTypes';
import {withNetwork} from '../../../components/OnyxProvider';
import networkPropTypes from '../../../components/networkPropTypes';
@@ -64,140 +65,142 @@ const defaultProps = {
reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps,
};
-class WorkspaceReimburseView extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- currentRatePerUnit: this.getCurrentRatePerUnitLabel(),
- };
- }
-
- componentDidMount() {
- this.fetchData();
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.policy.customUnits !== this.props.policy.customUnits || prevProps.preferredLocale !== this.props.preferredLocale) {
- this.setState({currentRatePerUnit: this.getCurrentRatePerUnitLabel()});
- }
-
- const reconnecting = prevProps.network.isOffline && !this.props.network.isOffline;
- if (!reconnecting) {
- return;
- }
+function WorkspaceReimburseView(props) {
+ const [currentRatePerUnit, setCurrentRatePerUnit] = useState('');
+ const prevIsOffline = usePrevious(props.network.isOffline);
+ const viewAllReceiptsUrl = `expenses?policyIDList=${props.policy.id}&billableReimbursable=reimbursable&submitterEmail=%2B%2B`;
+ const distanceCustomUnit = _.find(lodashGet(props.policy, 'customUnits', {}), (unit) => unit.name === 'Distance');
+ const distanceCustomRate = _.find(lodashGet(props.distanceCustomUnit, 'rates', {}), (rate) => rate.name === 'Default Rate');
+
+ const getNumericValue = useCallback(
+ (value) => {
+ const propsToLocaleDigit = props.toLocaleDigit;
+ const numValue = parseFloat(value.toString().replace(propsToLocaleDigit('.'), '.'));
+ if (Number.isNaN(numValue)) {
+ return NaN;
+ }
+ return numValue.toFixed(3);
+ },
+ [props.toLocaleDigit],
+ );
+
+ const getRateDisplayValue = useCallback(
+ (value) => {
+ const propsToLocaleDigit = props.toLocaleDigit;
+ const numValue = getNumericValue(value);
+ if (Number.isNaN(numValue)) {
+ return '';
+ }
+ return numValue.toString().replace('.', propsToLocaleDigit('.')).substring(0, value.length);
+ },
+ [getNumericValue, props.toLocaleDigit],
+ );
- this.fetchData();
- }
+ const getRateLabel = useCallback((customUnitRate) => getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET), [getRateDisplayValue]);
- getCurrentRatePerUnitLabel() {
- const distanceCustomUnit = _.find(lodashGet(this.props, 'policy.customUnits', {}), (unit) => unit.name === 'Distance');
- const customUnitRate = _.find(lodashGet(distanceCustomUnit, 'rates', {}), (rate) => rate.name === 'Default Rate');
- const currentUnit = this.getUnitLabel(lodashGet(distanceCustomUnit, 'attributes.unit', 'mi'));
- const currentRate = this.getRateLabel(customUnitRate);
- const perWord = this.props.translate('common.per');
+ const getUnitLabel = useCallback(
+ (value) => {
+ const propsTranslate = props.translate;
+ return propsTranslate(`common.${value}`);
+ },
+ [props.translate],
+ );
+
+ const getCurrentRatePerUnitLabel = useCallback(() => {
+ const propsTranslate = props.translate;
+ const customUnitRate = _.find(distanceCustomUnit && distanceCustomUnit.rates, (rate) => rate && rate.name === 'Default Rate');
+ const currentUnit = getUnitLabel((distanceCustomUnit && distanceCustomUnit.attributes && distanceCustomUnit.attributes.unit) || 'mi');
+ const currentRate = getRateLabel(customUnitRate);
+ const perWord = propsTranslate('common.per');
return `${currentRate} ${perWord} ${currentUnit}`;
- }
-
- getRateLabel(customUnitRate) {
- return this.getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET);
- }
-
- getUnitLabel(value) {
- return this.props.translate(`common.${value}`);
- }
-
- getRateDisplayValue(value) {
- const numValue = this.getNumericValue(value);
- if (Number.isNaN(numValue)) {
- return '';
- }
- return numValue.toString().replace('.', this.props.toLocaleDigit('.')).substring(0, value.length);
- }
-
- getNumericValue(value) {
- const numValue = parseFloat(value.toString().replace(this.props.toLocaleDigit('.'), '.'));
- if (Number.isNaN(numValue)) {
- return NaN;
- }
- return numValue.toFixed(3);
- }
+ }, [props.translate, distanceCustomUnit, getUnitLabel, getRateLabel]);
- fetchData() {
+ const fetchData = useCallback(() => {
// Instead of setting the reimbursement account loading within the optimistic data of the API command, use a separate action so that the Onyx value is updated right away.
// openWorkspaceReimburseView uses API.read which will not make the request until all WRITE requests in the sequential queue have finished responding, so there would be a delay in
// updating Onyx with the optimistic data.
+ const propsPolicyId = props.policy.id;
BankAccounts.setReimbursementAccountLoading(true);
- Policy.openWorkspaceReimburseView(this.props.policy.id);
- }
-
- render() {
- const viewAllReceiptsUrl = `expenses?policyIDList=${this.props.policy.id}&billableReimbursable=reimbursable&submitterEmail=%2B%2B`;
- const distanceCustomUnit = _.find(lodashGet(this.props, 'policy.customUnits', {}), (unit) => unit.name === 'Distance');
- const distanceCustomRate = _.find(lodashGet(distanceCustomUnit, 'rates', {}), (rate) => rate.name === 'Default Rate');
- return (
- <>
- Link.openOldDotLink(viewAllReceiptsUrl),
- icon: Expensicons.Receipt,
- shouldShowRightIcon: true,
- iconRight: Expensicons.NewWindow,
- wrapperStyle: [styles.cardMenuItem],
- link: () => Link.buildOldDotURL(viewAllReceiptsUrl),
- },
- ]}
- >
-
-
- {this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')}
-
- {this.props.translate('workspace.reimburse.captureNoVBACopyAfterEmail')}
-
-
-
-
-
-
- {this.props.translate('workspace.reimburse.trackDistanceCopy')}
-
-
- Navigation.navigate(ROUTES.getWorkspaceRateAndUnitRoute(this.props.policy.id))}
- wrapperStyle={[styles.mhn5, styles.wAuto]}
- brickRoadIndicator={(lodashGet(distanceCustomUnit, 'errors') || lodashGet(distanceCustomRate, 'errors')) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR}
+ Policy.openWorkspaceReimburseView(propsPolicyId);
+ }, [props.policy.id]);
+
+ useEffect(() => {
+ fetchData();
+ }, [fetchData]);
+
+ useEffect(() => {
+ setCurrentRatePerUnit(getCurrentRatePerUnitLabel());
+ const isReconnecting = prevIsOffline && !props.network.isOffline;
+ if (!isReconnecting) {
+ return;
+ }
+ fetchData();
+ }, [props.policy.customUnits, props.preferredLocale, props.network.isOffline, prevIsOffline, getCurrentRatePerUnitLabel, fetchData]);
+
+ return (
+ <>
+ Link.openOldDotLink(viewAllReceiptsUrl),
+ icon: Expensicons.Receipt,
+ shouldShowRightIcon: true,
+ iconRight: Expensicons.NewWindow,
+ wrapperStyle: [styles.cardMenuItem],
+ link: () => Link.buildOldDotURL(viewAllReceiptsUrl),
+ },
+ ]}
+ >
+
+
+ {props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')}
+
-
-
-
-
- >
- );
- }
+ {props.translate('workspace.reimburse.captureNoVBACopyAfterEmail')}
+
+
+
+
+
+
+ {props.translate('workspace.reimburse.trackDistanceCopy')}
+
+
+ Navigation.navigate(ROUTES.getWorkspaceRateAndUnitRoute(props.policy.id))}
+ wrapperStyle={[styles.mhn5, styles.wAuto]}
+ brickRoadIndicator={(lodashGet(distanceCustomUnit, 'errors') || lodashGet(distanceCustomRate, 'errors')) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR}
+ />
+
+
+
+
+ >
+ );
}
WorkspaceReimburseView.defaultProps = defaultProps;
WorkspaceReimburseView.propTypes = propTypes;
+WorkspaceReimburseView.displayName = 'WorkspaceReimburseView';
export default compose(
withLocalize,