Skip to content

Commit

Permalink
Merge pull request #6878 from parasharrajat/trans-amount-scaffold
Browse files Browse the repository at this point in the history
Add wallet balance transfer Page
  • Loading branch information
stitesExpensify authored Jan 13, 2022
2 parents 5afb3f2 + efeb43c commit 01757b2
Show file tree
Hide file tree
Showing 12 changed files with 416 additions and 25 deletions.
16 changes: 15 additions & 1 deletion src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,11 +390,20 @@ const CONST = {
},

WALLET: {
TRANSFER_BALANCE_FEE: 0.30,
TRANSFER_METHOD_TYPE: {
INSTANT: 'instant',
ACH: 'ach',
},
TRANSFER_METHOD_TYPE_FEE: {
INSTANT: {
RATE: 1.5,
MINIMUM_FEE: 25,
},
ACH: {
RATE: 0,
MINIMUM_FEE: 0,
},
},
ERROR: {
IDENTITY_NOT_FOUND: 'Identity not found',
INVALID_SSN: 'Invalid SSN',
Expand Down Expand Up @@ -466,6 +475,11 @@ const CONST = {
BANK_ACCOUNT: 'bankAccount',
},

PAYMENT_METHOD_ID_KEYS: {
DEBIT_CARD: 'fundID',
BANK_ACCOUNT: 'bankAccountID',
},

IOU: {
// Note: These payment types are used when building IOU reportAction message values in the server and should
// not be changed.
Expand Down
6 changes: 5 additions & 1 deletion src/components/CurrentWalletBalance.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ const propTypes = {
currentBalance: PropTypes.number,
}),

/** Styles of the amount */
balanceStyles: PropTypes.arrayOf(PropTypes.object),

...withLocalizePropTypes,
};

const defaultProps = {
userWallet: {},
balanceStyles: [],
};

const CurrentWalletBalance = (props) => {
Expand All @@ -41,7 +45,7 @@ const CurrentWalletBalance = (props) => {
);
return (
<Text
style={[styles.textXXXLarge, styles.pv5, styles.alignSelfCenter]}
style={[styles.textXXXLarge, styles.pv5, styles.alignSelfCenter, ...props.balanceStyles]}
>
{`${formattedBalance}`}
</Text>
Expand Down
2 changes: 1 addition & 1 deletion src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ export default {
transferAmountPage: {
transfer: ({amount}) => `Transfer${amount ? ` ${amount}` : ''}`,
instant: 'Instant (Debit Card)',
instantSummary: ({amount}) => `1.5% fee (${amount} minimum)`,
instantSummary: ({rate, minAmount}) => `${rate}% fee (${minAmount} minimum)`,
ach: '1-3 Business Days (Bank Account)',
achSummary: 'No fee',
whichAccount: 'Which Account?',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ export default {
transferAmountPage: {
transfer: ({amount}) => `Transferir${amount ? ` ${amount}` : ''}`,
instant: 'Instante',
instantSummary: ({amount}) => `Tarifa del 1.5% (${amount} mínimo)`,
instantSummary: ({rate, minAmount}) => `Tarifa del ${rate}% (${minAmount} mínimo)`,
ach: '1-3 días laborales',
achSummary: 'Sin cargo',
whichAccount: '¿Que cuenta?',
Expand Down
20 changes: 17 additions & 3 deletions src/libs/PaymentUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ function hasExpensifyPaymentMethod(cardList = [], bankAccountList = []) {
* @param {Array} bankAccountList
* @param {Array} cardList
* @param {String} [payPalMeUsername='']
* @returns {Array<PaymentMethod>}
* @returns {Array<Object>}
*/
function getPaymentMethods(bankAccountList, cardList, payPalMeUsername = '') {
function formatPaymentMethods(bankAccountList, cardList, payPalMeUsername = '') {
const combinedPaymentMethods = [];

_.each(bankAccountList, (bankAccount) => {
Expand Down Expand Up @@ -79,7 +79,21 @@ function getPaymentMethods(bankAccountList, cardList, payPalMeUsername = '') {
return combinedPaymentMethods;
}

/**
* @param {Number} currentBalance
* @param {String} methodType
* @returns {Number}
*/
function calculateWalletTransferBalanceFee(currentBalance, methodType) {
const transferMethodTypeFeeStructure = methodType === CONST.WALLET.TRANSFER_METHOD_TYPE.INSTANT
? CONST.WALLET.TRANSFER_METHOD_TYPE_FEE.INSTANT
: CONST.WALLET.TRANSFER_METHOD_TYPE_FEE.ACH;
const calculateFee = (currentBalance * transferMethodTypeFeeStructure.RATE) / 100;
return Math.max(calculateFee, transferMethodTypeFeeStructure.MINIMUM_FEE);
}

export {
hasExpensifyPaymentMethod,
getPaymentMethods,
formatPaymentMethods,
calculateWalletTransferBalanceFee,
};
58 changes: 58 additions & 0 deletions src/libs/actions/PaymentMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Growl from '../Growl';
import * as Localize from '../Localize';
import Navigation from '../Navigation/Navigation';
import * as CardUtils from '../CardUtils';
import ROUTES from '../../ROUTES';

/**
* Sets up a ref to an instance of the KYC Wall component.
Expand Down Expand Up @@ -114,10 +115,67 @@ function clearDebitCardFormErrorAndSubmit() {
});
}

/**
* Call the API to transfer wallet balance.
* @param {Object} paymentMethod
* @param {*} paymentMethod.methodID
* @param {String} paymentMethod.type
*/
function transferWalletBalance(paymentMethod) {
const paymentMethodIDKey = paymentMethod.type === CONST.PAYMENT_METHODS.BANK_ACCOUNT
? CONST.PAYMENT_METHOD_ID_KEYS.BANK_ACCOUNT
: CONST.PAYMENT_METHOD_ID_KEYS.DEBIT_CARD;
const parameters = {
[paymentMethodIDKey]: paymentMethod.methodID,
};
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {loading: true});

API.TransferWalletBalance(parameters)
.then((response) => {
if (response.jsonCode !== 200) {
throw new Error(response.message);
}
Onyx.merge(ONYXKEYS.USER_WALLET, {balance: 0});
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {shouldShowConfirmModal: true, loading: false});
Navigation.navigate(ROUTES.SETTINGS_PAYMENTS);
}).catch(() => {
Growl.error(Localize.translateLocal('transferAmountPage.failedTransfer'));
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {loading: false});
});
}

/**
* Set the transfer account and reset the transfer data for Wallet balance transfer
* @param {String} selectedAccountID
*/
function saveWalletTransferAccountAndResetData(selectedAccountID) {
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {
selectedAccountID,
filterPaymentMethodType: null,
loading: false,
shouldShowConfirmModal: false,
});
}

/**
* @param {Number} transferAmount
*/
function saveWalletTransferAmount(transferAmount) {
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {transferAmount});
}

function dismissWalletConfirmModal() {
Onyx.merge(ONYXKEYS.WALLET_TRANSFER, {shouldShowConfirmModal: false});
}

export {
getPaymentMethods,
addBillingCard,
kycWallRef,
continueSetup,
clearDebitCardFormErrorAndSubmit,
transferWalletBalance,
saveWalletTransferAccountAndResetData,
saveWalletTransferAmount,
dismissWalletConfirmModal,
};
2 changes: 1 addition & 1 deletion src/pages/settings/Payments/PaymentMethodList.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class PaymentMethodList extends Component {
* @returns {Array}
*/
createPaymentMethodList() {
let combinedPaymentMethods = PaymentUtils.getPaymentMethods(this.props.bankAccountList, this.props.cardList, this.props.payPalMeUsername);
let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(this.props.bankAccountList, this.props.cardList, this.props.payPalMeUsername);
combinedPaymentMethods = _.map(combinedPaymentMethods, paymentMethod => ({
...paymentMethod,
type: MENU_ITEM,
Expand Down
49 changes: 45 additions & 4 deletions src/pages/settings/Payments/PaymentsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,28 @@ import ONYXKEYS from '../../../ONYXKEYS';
import Permissions from '../../../libs/Permissions';
import AddPaymentMethodMenu from '../../../components/AddPaymentMethodMenu';
import CONST from '../../../CONST';
import * as Expensicons from '../../../components/Icon/Expensicons';
import MenuItem from '../../../components/MenuItem';
import walletTransferPropTypes from './walletTransferPropTypes';
import ConfirmModal from '../../../components/ConfirmModal';

const propTypes = {
...withLocalizePropTypes,
/** Wallet balance transfer props */
walletTransfer: walletTransferPropTypes,

/** List of betas available to current user */
betas: PropTypes.arrayOf(PropTypes.string),

/** Are we loading payment methods? */
isLoadingPaymentMethods: PropTypes.bool,

...withLocalizePropTypes,
};

const defaultProps = {
walletTransfer: {
shouldShowConfirmModal: false,
},
betas: [],
isLoadingPaymentMethods: true,
};
Expand All @@ -48,6 +58,7 @@ class PaymentsPage extends React.Component {
this.paymentMethodPressed = this.paymentMethodPressed.bind(this);
this.addPaymentMethodTypePressed = this.addPaymentMethodTypePressed.bind(this);
this.hideAddPaymentMenu = this.hideAddPaymentMenu.bind(this);
this.navigateToTransferBalancePage = this.navigateToTransferBalancePage.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -110,6 +121,10 @@ class PaymentsPage extends React.Component {
this.setState({shouldShowAddPaymentMenu: false});
}

navigateToTransferBalancePage() {
Navigation.navigate(ROUTES.SETTINGS_PAYMENTS_TRANSFER_BALANCE);
}

render() {
return (
<ScreenWrapper>
Expand All @@ -121,9 +136,19 @@ class PaymentsPage extends React.Component {
onCloseButtonPress={() => Navigation.dismissModal(true)}
/>
<View style={styles.flex1}>
{
Permissions.canUseWallet(this.props.betas) && <CurrentWalletBalance />
}
{Permissions.canUseWallet(this.props.betas) && (
<>
<View style={[styles.mv5]}>
<CurrentWalletBalance />
</View>
<MenuItem
title={this.props.translate('common.transferBalance')}
icon={Expensicons.Transfer}
onPress={this.navigateToTransferBalancePage}
shouldShowRightIcon
/>
</>
)}
<Text
style={[styles.ph5, styles.formLabel]}
>
Expand All @@ -145,6 +170,19 @@ class PaymentsPage extends React.Component {
}}
onItemSelected={method => this.addPaymentMethodTypePressed(method)}
/>
<ConfirmModal
title={this.props.translate('paymentsPage.allSet')}
onConfirm={PaymentMethods.dismissWalletConfirmModal}
isVisible={this.props.walletTransfer.shouldShowConfirmModal}
prompt={this.props.translate('paymentsPage.transferConfirmText', {
amount: this.props.numberFormat(
this.props.walletTransfer.transferAmount / 100,
{style: 'currency', currency: 'USD'},
),
})}
confirmText={this.props.translate('paymentsPage.gotIt')}
shouldShowCancelButton={false}
/>
</KeyboardAvoidingView>
</ScreenWrapper>
);
Expand All @@ -160,6 +198,9 @@ export default compose(
betas: {
key: ONYXKEYS.BETAS,
},
walletTransfer: {
key: ONYXKEYS.WALLET_TRANSFER,
},
isLoadingPaymentMethods: {
key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS,
initWithStoredValues: false,
Expand Down
Loading

0 comments on commit 01757b2

Please sign in to comment.