-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Feature: Transfer balance #4177
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
Changes from all commits
465db11
a094ac4
6b5e413
4caaeeb
6312af1
981faee
46739f1
360808e
1022e5e
ebef54c
596835c
389ddaf
62f8bbf
38052af
10b4d1b
f3f9973
8f7f20a
c593bae
c0bfe28
e9e303d
88d1b66
a96ef09
8551692
7c66493
324960b
62813f3
e41a044
5317be3
3216524
710be34
6bf8335
7787b7c
25bda90
b708e61
e1407c0
427990d
419d2c3
52ca3fe
aa9075b
6f26ee9
f12c40f
48c4c0d
747197e
eaa00c6
e016f45
57b22d8
83f9bf0
48d330d
419ab92
5a893ae
05520cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,8 @@ export default { | |
| SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', | ||
| SETTINGS_PAYMENTS: 'settings/payments', | ||
| SETTINGS_ADD_PAYPAL_ME: 'settings/payments/add-paypal-me', | ||
| SETTINGS_TRANSFER_BALANCE: 'settings/payments/transfer-balance', | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| SETTINGS_PAYMENTS_CHOOSE_TRANSFER_ACCOUNT: 'settings/payments/choose-transfer-account', | ||
| SETTINGS_ADD_DEBIT_CARD: 'settings/payments/add-debit-card', | ||
| SETTINGS_ADD_BANK_ACCOUNT: 'settings/payments/add-bank-account', | ||
| SETTINGS_ADD_LOGIN: 'settings/addlogin/:type', | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import React from 'react'; | ||
| import React, {Component} from 'react'; | ||
| import PropTypes from 'prop-types'; | ||
| import {withOnyx} from 'react-native-onyx'; | ||
| import Popover from './Popover'; | ||
|
|
@@ -9,54 +9,166 @@ import styles from '../styles/styles'; | |
| import compose from '../libs/compose'; | ||
| import ONYXKEYS from '../ONYXKEYS'; | ||
| import CONST from '../CONST'; | ||
| import * as StyleUtils from '../styles/StyleUtils'; | ||
| import getClickedElementLocation from '../libs/getClickedElementLocation'; | ||
| import ROUTES from '../ROUTES'; | ||
| import Navigation from '../libs/Navigation/Navigation'; | ||
|
|
||
| const propTypes = { | ||
| isVisible: PropTypes.bool.isRequired, | ||
| onClose: PropTypes.func.isRequired, | ||
| anchorPosition: PropTypes.shape({ | ||
| top: PropTypes.number, | ||
| left: PropTypes.number, | ||
| }), | ||
|
|
||
| const propTypes = { | ||
| /** Username for PayPal.Me */ | ||
| payPalMeUsername: PropTypes.string, | ||
|
|
||
| /** Type to filter the payment Method list */ | ||
| filterType: PropTypes.oneOf([CONST.PAYMENT_METHODS.DEBIT_CARD, CONST.PAYMENT_METHODS.BANK_ACCOUNT, '']), | ||
|
|
||
| /** Are we loading payments from the server? */ | ||
| isLoadingPayments: PropTypes.bool, | ||
|
|
||
| ...withLocalizePropTypes, | ||
| }; | ||
|
|
||
| const defaultProps = { | ||
| anchorPosition: {}, | ||
| payPalMeUsername: '', | ||
| filterType: '', | ||
| isLoadingPayments: false, | ||
| }; | ||
|
|
||
| const AddPaymentMethodMenu = props => ( | ||
| <Popover | ||
| isVisible={props.isVisible} | ||
| onClose={props.onClose} | ||
| anchorPosition={props.anchorPosition} | ||
| > | ||
| <MenuItem | ||
| title={props.translate('common.bankAccount')} | ||
| icon={Expensicons.Bank} | ||
| onPress={() => props.onItemSelected(CONST.PAYMENT_METHODS.BANK_ACCOUNT)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| <MenuItem | ||
| title={props.translate('common.debitCard')} | ||
| icon={Expensicons.CreditCard} | ||
| onPress={() => props.onItemSelected(CONST.PAYMENT_METHODS.DEBIT_CARD)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| {!props.payPalMeUsername && ( | ||
| <MenuItem | ||
| title={props.translate('common.payPalMe')} | ||
| icon={Expensicons.PayPal} | ||
| onPress={() => props.onItemSelected(CONST.PAYMENT_METHODS.PAYPAL)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| )} | ||
| </Popover> | ||
| ); | ||
| class AddPaymentMethodMenu extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
|
|
||
| this.state = { | ||
| isAddPaymentMenuActive: false, | ||
| anchorPosition: { | ||
| top: 0, | ||
| left: 0, | ||
| }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to use this component in this PR and having it internally track the |
||
| }; | ||
| this.addPaymentMethodPressed = this.addPaymentMethodPressed.bind(this); | ||
| this.addPaymentMethodTypePressed = this.addPaymentMethodTypePressed.bind(this); | ||
| this.hideAddPaymentMenu = this.hideAddPaymentMenu.bind(this); | ||
| } | ||
|
|
||
| /** | ||
| * Get the AddPaymentMethod Button title | ||
| * @returns {String} | ||
| */ | ||
| getAddPaymentMethodButtonTitle() { | ||
| switch (this.props.filterType) { | ||
| case CONST.PAYMENT_METHODS.BANK_ACCOUNT: | ||
| return this.props.translate('paymentMethodList.addBankAccount'); | ||
| case CONST.PAYMENT_METHODS.DEBIT_CARD: | ||
| return this.props.translate('paymentMethodList.addDebitCard'); | ||
| default: break; | ||
| } | ||
| return this.props.translate('paymentMethodList.addPaymentMethod'); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to make a new component that:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest calling it
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I didn't get it and I don't have access to that issue. But I got the idea.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I'm sorry, I forgot that you cannot see those issues. |
||
|
|
||
| /** | ||
| * Display the add payment method menu | ||
| * @param {Object} nativeEvent | ||
| */ | ||
| addPaymentMethodPressed(nativeEvent) { | ||
| const position = getClickedElementLocation(nativeEvent); | ||
| this.setState({ | ||
| isAddPaymentMenuActive: true, | ||
| anchorPosition: { | ||
| top: position.bottom, | ||
|
|
||
| // We want the position to be 20px to the right of the left border | ||
| left: position.left + 20, | ||
| }, | ||
| }); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would need to go into that other component. |
||
|
|
||
| /** | ||
| * Navigate to the appropriate payment type addition screen | ||
| * @param {String} paymentType | ||
| */ | ||
| addPaymentMethodTypePressed(paymentType) { | ||
| if (!this.props.filterType) { | ||
| this.hideAddPaymentMenu(); | ||
| } | ||
|
|
||
| if (paymentType === CONST.PAYMENT_METHODS.PAYPAL) { | ||
| Navigation.navigate(ROUTES.SETTINGS_ADD_PAYPAL_ME); | ||
| return; | ||
| } | ||
|
|
||
| if (paymentType === CONST.PAYMENT_METHODS.DEBIT_CARD) { | ||
| Navigation.navigate(ROUTES.SETTINGS_ADD_DEBIT_CARD); | ||
| return; | ||
| } | ||
|
|
||
| if (paymentType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) { | ||
| Navigation.navigate(ROUTES.SETTINGS_ADD_BANK_ACCOUNT); | ||
| return; | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of these routes should be in this component because we will eventually need to navigate to different routes depending on the context in which this component will be used. I would suggest passing in the route as a prop to keep this component reusable. |
||
|
|
||
| throw new Error('Invalid payment method type selected'); | ||
| } | ||
|
|
||
| /** | ||
| * Hide the add payment modal | ||
| */ | ||
| hideAddPaymentMenu() { | ||
| this.setState({isAddPaymentMenuActive: false}); | ||
| } | ||
|
|
||
| render() { | ||
| const addPaymentMethodButtonTitle = this.getAddPaymentMethodButtonTitle(); | ||
|
|
||
| return ( | ||
| <> | ||
| <MenuItem | ||
| onPress={e => (this.props.filterType | ||
| ? this.addPaymentMethodTypePressed(this.props.filterType) | ||
| : this.addPaymentMethodPressed(e) | ||
| )} | ||
| title={addPaymentMethodButtonTitle} | ||
| icon={Expensicons.Plus} | ||
| disabled={this.props.isLoadingPayments} | ||
| iconFill={this.state.isAddPaymentMenuActive | ||
| ? StyleUtils.getIconFillColor(CONST.BUTTON_STATES.PRESSED) | ||
| : undefined} | ||
| wrapperStyle={this.state.isAddPaymentMenuActive | ||
| ? [StyleUtils.getButtonBackgroundColorStyle(CONST.BUTTON_STATES.PRESSED)] | ||
| : []} | ||
|
|
||
| /> | ||
| {!this.props.filterType && ( | ||
| <Popover | ||
| isVisible={this.state.isAddPaymentMenuActive} | ||
| onClose={this.hideAddPaymentMenu} | ||
| anchorPosition={this.state.anchorPosition} | ||
| > | ||
| <MenuItem | ||
| title={this.props.translate('common.bankAccount')} | ||
| icon={Expensicons.Bank} | ||
| onPress={() => this.addPaymentMethodTypePressed(CONST.PAYMENT_METHODS.BANK_ACCOUNT)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| <MenuItem | ||
| title={this.props.translate('common.debitCard')} | ||
| icon={Expensicons.CreditCard} | ||
| onPress={() => this.addPaymentMethodTypePressed(CONST.PAYMENT_METHODS.DEBIT_CARD)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| {!this.props.payPalMeUsername && ( | ||
| <MenuItem | ||
| title={this.props.translate('common.payPalMe')} | ||
| icon={Expensicons.PayPal} | ||
| onPress={() => this.addPaymentMethodTypePressed(CONST.PAYMENT_METHODS.PAYPAL)} | ||
| wrapperStyle={styles.pr15} | ||
| /> | ||
| )} | ||
| </Popover> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| AddPaymentMethodMenu.propTypes = propTypes; | ||
| AddPaymentMethodMenu.defaultProps = defaultProps; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,14 +13,12 @@ import Avatar from './Avatar'; | |
| import Badge from './Badge'; | ||
| import CONST from '../CONST'; | ||
| import menuItemPropTypes from './menuItemPropTypes'; | ||
|
|
||
| const propTypes = { | ||
| ...menuItemPropTypes, | ||
| }; | ||
| import SelectCircle from './SelectCircle'; | ||
|
|
||
| const defaultProps = { | ||
| badgeText: undefined, | ||
| shouldShowRightIcon: false, | ||
| shouldShowSelectedState: false, | ||
| wrapperStyle: [], | ||
| success: false, | ||
| icon: undefined, | ||
|
|
@@ -32,6 +30,7 @@ const defaultProps = { | |
| iconFill: undefined, | ||
| focused: false, | ||
| disabled: false, | ||
| isSelected: false, | ||
| subtitle: undefined, | ||
| iconType: 'icon', | ||
| onPress: () => {}, | ||
|
|
@@ -124,13 +123,14 @@ const MenuItem = props => ( | |
| /> | ||
| </View> | ||
| )} | ||
| {props.shouldShowSelectedState && <SelectCircle isChecked={props.isSelected} />} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just FYI I tried to help out a bit and moved this change to a new PR to lighten things up here. |
||
| </View> | ||
| </> | ||
| )} | ||
| </Pressable> | ||
| ); | ||
|
|
||
| MenuItem.propTypes = propTypes; | ||
| MenuItem.propTypes = menuItemPropTypes; | ||
| MenuItem.defaultProps = defaultProps; | ||
| MenuItem.displayName = 'MenuItem'; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import React from 'react'; | ||
| import {View} from 'react-native'; | ||
| import PropTypes from 'prop-types'; | ||
| import styles from '../styles/styles'; | ||
| import Icon from './Icon'; | ||
| import * as Expensicons from './Icon/Expensicons'; | ||
| import themeColors from '../styles/themes/default'; | ||
|
|
||
| const propTypes = { | ||
| /** Whether SelectCircle is checked */ | ||
| isChecked: PropTypes.bool, | ||
| }; | ||
|
|
||
| const defaultProps = { | ||
| isChecked: false, | ||
| }; | ||
|
|
||
| const SelectCircle = props => ( | ||
| <View style={[styles.selectCircle, styles.alignSelfCenter]}> | ||
| {props.isChecked && ( | ||
| <Icon src={Expensicons.Checkmark} fill={themeColors.iconSuccessFill} /> | ||
| )} | ||
| </View> | ||
| ); | ||
|
|
||
| SelectCircle.propTypes = propTypes; | ||
| SelectCircle.defaultProps = defaultProps; | ||
| SelectCircle.displayName = 'SelectCircle'; | ||
|
|
||
| export default SelectCircle; |
Uh oh!
There was an error while loading. Please reload this page.