Skip to content

Commit 2f679df

Browse files
committed
more clean up
Use recipient because it explains the significance of props.participants[0] better Define whether to use venmo or paypal via props; Clean up currency code changes lesss changes
1 parent c1d2c39 commit 2f679df

File tree

4 files changed

+193
-240
lines changed

4 files changed

+193
-240
lines changed

src/components/ButtonWithMenu.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ const propTypes = {
1414
/** Callback to execute when the main button is pressed */
1515
onPress: PropTypes.func.isRequired,
1616

17-
/** Callback to execute when a menu item is selected */
18-
onChange: PropTypes.func,
19-
2017
/** Whether we should show a loading state for the main button */
2118
isLoading: PropTypes.bool,
2219

@@ -26,6 +23,7 @@ const propTypes = {
2623
/** Menu options to display */
2724
/** e.g. [{text: 'Pay with Expensify', icon: Wallet}, {text: 'PayPal', icon: PayPal}, {text: 'Venmo', icon: Venmo}] */
2825
options: PropTypes.arrayOf(PropTypes.shape({
26+
value: PropTypes.string.isRequired,
2927
text: PropTypes.string.isRequired,
3028
icon: PropTypes.elementType,
3129
iconWidth: PropTypes.number,
@@ -35,7 +33,6 @@ const propTypes = {
3533
};
3634

3735
const defaultProps = {
38-
onChange: () => {},
3936
isLoading: false,
4037
isDisabled: false,
4138
menuHeaderText: '',
@@ -63,7 +60,7 @@ class ButtonWithMenu extends PureComponent {
6360
<ButtonWithDropdown
6461
buttonText={selectedItemText}
6562
isLoading={this.props.isLoading}
66-
onButtonPress={this.props.onPress}
63+
onButtonPress={() => this.props.onPress(this.state.selectedItem.value)}
6764
onDropdownPress={() => {
6865
this.setMenuVisibility(true);
6966
}}
@@ -75,7 +72,7 @@ class ButtonWithMenu extends PureComponent {
7572
style={[styles.w100]}
7673
isLoading={this.props.isLoading}
7774
text={selectedItemText}
78-
onPress={this.props.onPress}
75+
onPress={() => this.props.onPress(this.props.options[0].value)}
7976
pressOnEnter
8077
/>
8178
)}
@@ -92,7 +89,6 @@ class ButtonWithMenu extends PureComponent {
9289
...item,
9390
onSelected: () => {
9491
this.setState({selectedItem: item});
95-
this.props.onChange(item);
9692
},
9793
}))}
9894
/>

src/components/IOUConfirmationList.js

Lines changed: 29 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ import FixedFooter from './FixedFooter';
1717
import ExpensiTextInput from './ExpensiTextInput';
1818
import CONST from '../CONST';
1919
import ButtonWithMenu from './ButtonWithMenu';
20-
import * as Expensicons from './Icon/Expensicons';
21-
import Permissions from '../libs/Permissions';
22-
import isAppInstalled from '../libs/isAppInstalled';
23-
import * as ValidationUtils from '../libs/ValidationUtils';
24-
import makeCancellablePromise from '../libs/MakeCancellablePromise';
20+
import SettlementButton from './SettlementButton';
2521

2622
const propTypes = {
2723
/** Callback to inform parent modal of success */
@@ -118,38 +114,20 @@ class IOUConfirmationList extends Component {
118114
constructor(props) {
119115
super(props);
120116

121-
const formattedParticipants = _.map(this.getParticipantsWithAmount(this.props.participants), participant => ({
117+
const formattedParticipants = _.map(this.getParticipantsWithAmount(props.participants), participant => ({
122118
...participant, selected: true,
123119
}));
124120

125-
// Add the button options to payment menu
126-
const confirmationButtonOptions = [];
127-
let defaultButtonOption = {
128-
text: this.props.translate(this.props.hasMultipleParticipants ? 'iou.split' : 'iou.request', {
129-
amount: this.props.numberFormat(
130-
this.props.iouAmount,
131-
{style: 'currency', currency: this.props.iou.selectedCurrencyCode},
121+
this.splitOrRequestOptions = [{
122+
text: props.translate(props.hasMultipleParticipants ? 'iou.split' : 'iou.request', {
123+
amount: props.numberFormat(
124+
props.iouAmount,
125+
{style: 'currency', currency: props.iou.selectedCurrencyCode},
132126
),
133127
}),
134-
};
135-
if (this.props.iouType === CONST.IOU.IOU_TYPE.SEND && this.props.participants.length === 1 && Permissions.canUseIOUSend(this.props.betas)) {
136-
// Add the Expensify Wallet option if available and make it the first option
137-
if (this.props.localCurrencyCode === CONST.CURRENCY.USD && Permissions.canUsePayWithExpensify(this.props.betas) && Permissions.canUseWallet(this.props.betas)) {
138-
confirmationButtonOptions.push({text: this.props.translate('iou.settleExpensify'), icon: Expensicons.Wallet});
139-
}
140-
141-
// Add PayPal option
142-
if (this.props.participants[0].payPalMeAddress) {
143-
confirmationButtonOptions.push({text: this.props.translate('iou.settlePaypalMe'), icon: Expensicons.PayPal});
144-
}
145-
defaultButtonOption = {text: this.props.translate('iou.settleElsewhere'), icon: Expensicons.Cash};
146-
}
147-
confirmationButtonOptions.push(defaultButtonOption);
148-
149-
this.checkVenmoAvailabilityPromise = null;
128+
}];
150129

151130
this.state = {
152-
confirmationButtonOptions,
153131
participants: formattedParticipants,
154132
};
155133

@@ -161,22 +139,6 @@ class IOUConfirmationList extends Component {
161139
// We need to wait for the transition animation to end before focusing the TextInput,
162140
// otherwise the TextInput isn't animated correctly
163141
setTimeout(() => this.textInput.focus(), CONST.ANIMATED_TRANSITION);
164-
165-
// Only add the Venmo option if we're sending a payment
166-
if (this.props.iouType !== CONST.IOU.IOU_TYPE.SEND) {
167-
return;
168-
}
169-
170-
this.addVenmoPaymentOptionToMenu();
171-
}
172-
173-
componentWillUnmount() {
174-
if (!this.checkVenmoAvailabilityPromise) {
175-
return;
176-
}
177-
178-
this.checkVenmoAvailabilityPromise.cancel();
179-
this.checkVenmoAvailabilityPromise = null;
180142
}
181143

182144
/**
@@ -329,31 +291,6 @@ class IOUConfirmationList extends Component {
329291
];
330292
}
331293

332-
/**
333-
* Adds Venmo, if available, as the second option in the menu of payment options
334-
*/
335-
addVenmoPaymentOptionToMenu() {
336-
if (this.props.localCurrencyCode !== CONST.CURRENCY.USD || !this.state.participants[0].phoneNumber || !ValidationUtils.isValidUSPhone(this.state.participants[0].phoneNumber)) {
337-
return;
338-
}
339-
340-
this.checkVenmoAvailabilityPromise = makeCancellablePromise(isAppInstalled('venmo'));
341-
this.checkVenmoAvailabilityPromise
342-
.promise
343-
.then((isVenmoInstalled) => {
344-
if (!isVenmoInstalled) {
345-
return;
346-
}
347-
348-
this.setState(prevState => ({
349-
confirmationButtonOptions: [...prevState.confirmationButtonOptions.slice(0, 1),
350-
{text: this.props.translate('iou.settleVenmo'), icon: Expensicons.Venmo},
351-
...prevState.confirmationButtonOptions.slice(1),
352-
],
353-
}));
354-
});
355-
}
356-
357294
/**
358295
* Calculates the amount per user given a list of participants
359296
* @param {Array} participants
@@ -403,6 +340,10 @@ class IOUConfirmationList extends Component {
403340
const hoverStyle = this.props.hasMultipleParticipants ? styles.hoveredComponentBG : {};
404341
const toggleOption = this.props.hasMultipleParticipants ? this.toggleOption : undefined;
405342
const selectedParticipants = this.getSelectedParticipants();
343+
const shouldShowSettlementButton = this.props.iouType === CONST.IOU.IOU_TYPE.SEND;
344+
const shouldDisableButton = selectedParticipants.length === 0 || this.props.network.isOffline;
345+
const isLoading = this.props.iou.loading && !this.props.network.isOffline;
346+
const recipient = this.state.participants[0];
406347
return (
407348
<>
408349
<ScrollView style={[styles.flexGrow0, styles.flexShrink1, styles.flexBasisAuto, styles.w100]}>
@@ -435,12 +376,23 @@ class IOUConfirmationList extends Component {
435376
{this.props.translate('session.offlineMessage')}
436377
</ExpensifyText>
437378
)}
438-
<ButtonWithMenu
439-
options={this.state.confirmationButtonOptions}
440-
isDisabled={selectedParticipants.length === 0 || this.props.network.isOffline}
441-
isLoading={this.props.iou.loading && !this.props.network.isOffline}
442-
onPress={this.onPress}
443-
/>
379+
{shouldShowSettlementButton ? (
380+
<SettlementButton
381+
isDisabled={shouldDisableButton}
382+
isLoading={this.props.iou.loading && !this.props.network.isOffline}
383+
onPress={this.onPress}
384+
shouldShowPaypal={Boolean(recipient.payPalMeAddress)}
385+
recipientPhoneNumber={recipient.phoneNumber}
386+
currency={this.props.localCurrencyCode}
387+
/>
388+
) : (
389+
<ButtonWithMenu
390+
isDisabled={shouldDisableButton}
391+
isLoading={isLoading}
392+
onPress={this.onPress}
393+
options={this.splitOrRequestOptions}
394+
/>
395+
)}
444396
</FixedFooter>
445397
</>
446398
);

src/components/SettlementButton.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import {withOnyx} from 'react-native-onyx';
4+
import ButtonWithMenu from './ButtonWithMenu';
5+
import * as Expensicons from './Icon/Expensicons';
6+
import Permissions from '../libs/Permissions';
7+
import isAppInstalled from '../libs/isAppInstalled';
8+
import * as ValidationUtils from '../libs/ValidationUtils';
9+
import makeCancellablePromise from '../libs/MakeCancellablePromise';
10+
import ONYXKEYS from '../ONYXKEYS';
11+
import CONST from '../CONST';
12+
import compose from '../libs/compose';
13+
import withLocalize, {withLocalizePropTypes} from './withLocalize';
14+
15+
const propTypes = {
16+
/** Settlement currency type */
17+
currency: PropTypes.string,
18+
19+
/** Should we show paypal option */
20+
shouldShowPaypal: PropTypes.bool,
21+
22+
/** Associated phone login for the person we are sending money to */
23+
recipientPhoneNumber: PropTypes.string,
24+
25+
...withLocalizePropTypes,
26+
};
27+
28+
const defaultProps = {
29+
currency: CONST.CURRENCY.USD,
30+
recipientPhoneNumber: '',
31+
shouldShowPaypal: false,
32+
};
33+
34+
class SettlementButton extends React.Component {
35+
constructor(props) {
36+
super(props);
37+
38+
const buttonOptions = [];
39+
40+
if (props.currency === CONST.CURRENCY.USD && Permissions.canUsePayWithExpensify(props.betas) && Permissions.canUseWallet(props.betas)) {
41+
buttonOptions.push({
42+
text: props.translate('iou.settleExpensify'),
43+
icon: Expensicons.Wallet,
44+
value: CONST.IOU.PAYMENT_TYPE.EXPENSIFY,
45+
});
46+
}
47+
48+
if (props.shouldShowPaypal) {
49+
buttonOptions.push({
50+
text: props.translate('iou.settlePaypalMe'),
51+
icon: Expensicons.PayPal,
52+
value: CONST.IOU.PAYMENT_TYPE.PAYPAL_ME,
53+
});
54+
}
55+
56+
buttonOptions.push({
57+
text: props.translate('iou.settleElsewhere'),
58+
icon: Expensicons.Cash,
59+
value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE,
60+
});
61+
62+
// Venmo requires an async call to the native layer to determine availability and will be added as an option if available.
63+
this.checkVenmoAvailabilityPromise = null;
64+
65+
this.state = {
66+
buttonOptions,
67+
};
68+
}
69+
70+
componentDidMount() {
71+
this.addVenmoPaymentOptionToMenu();
72+
}
73+
74+
componentWillUnmount() {
75+
if (!this.checkVenmoAvailabilityPromise) {
76+
return;
77+
}
78+
79+
this.checkVenmoAvailabilityPromise.cancel();
80+
this.checkVenmoAvailabilityPromise = null;
81+
}
82+
83+
/**
84+
* @returns {Boolean}
85+
*/
86+
doesRecipientHaveValidPhoneLogin() {
87+
return this.props.recipientPhoneNumber && ValidationUtils.isValidUSPhone(this.props.recipientPhoneNumber);
88+
}
89+
90+
/**
91+
* Adds Venmo, if available, as the second option in the menu of payment options
92+
*/
93+
addVenmoPaymentOptionToMenu() {
94+
if (this.props.currency !== CONST.CURRENCY.USD || !this.doesRecipientHaveValidPhoneLogin()) {
95+
return;
96+
}
97+
98+
this.checkVenmoAvailabilityPromise = makeCancellablePromise(isAppInstalled('venmo'));
99+
this.checkVenmoAvailabilityPromise
100+
.promise
101+
.then((isVenmoInstalled) => {
102+
if (!isVenmoInstalled) {
103+
return;
104+
}
105+
106+
this.setState(prevState => ({
107+
buttonOptions: [...prevState.buttonOptions.slice(0, 1),
108+
{
109+
text: this.props.translate('iou.settleVenmo'),
110+
icon: Expensicons.Venmo,
111+
value: CONST.IOU.PAYMENT_TYPE.VENMO,
112+
},
113+
...prevState.buttonOptions.slice(1),
114+
],
115+
}));
116+
});
117+
}
118+
119+
render() {
120+
return (
121+
<ButtonWithMenu
122+
isDisabled={this.props.isDisabled}
123+
isLoading={this.props.isLoading}
124+
onPress={this.props.onPress}
125+
options={this.state.buttonOptions}
126+
/>
127+
);
128+
}
129+
}
130+
131+
SettlementButton.propTypes = propTypes;
132+
SettlementButton.defaultProps = defaultProps;
133+
134+
export default compose(
135+
withLocalize,
136+
withOnyx({
137+
betas: {
138+
key: ONYXKEYS.BETAS,
139+
},
140+
}),
141+
)(SettlementButton);

0 commit comments

Comments
 (0)