Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
68395a0
Extend wallet balance to take style prop
parasharrajat Dec 22, 2021
d0d742e
add wallet transfer actions
parasharrajat Dec 22, 2021
e89e58e
add prop types
parasharrajat Dec 22, 2021
a616f37
Create wallet transfer page
parasharrajat Dec 22, 2021
7967331
Add option to navigate to transfer balance page from payments page
parasharrajat Dec 22, 2021
b541e5c
fix crash
parasharrajat Dec 22, 2021
1ccd2f7
Add the confirm transfer dialog
parasharrajat Dec 22, 2021
11b8df1
clean up
parasharrajat Dec 22, 2021
dce8300
Pull latest changes from main
parasharrajat Dec 29, 2021
0998c3d
Remove extra functions in Onyx data
parasharrajat Dec 29, 2021
1408f61
Rename lint error
parasharrajat Dec 29, 2021
6105dd5
Props definition correction
parasharrajat Dec 29, 2021
2464a57
refactor transferbalance page
parasharrajat Dec 29, 2021
a36bd7b
Refactor Onyx Keys
parasharrajat Dec 29, 2021
2050722
rename the method
parasharrajat Dec 29, 2021
f2c2765
more cleanup
parasharrajat Dec 29, 2021
3225c7e
Refactor code to match styleguide
parasharrajat Dec 30, 2021
66f3bfb
comments
parasharrajat Dec 30, 2021
00fb74c
Merge branch 'main' of github.com:Expensify/Expensify.cash into trans…
parasharrajat Jan 8, 2022
66ba6bc
correct Balance calculation
parasharrajat Jan 8, 2022
437e0c3
Fix: Transfer balance method check and API call
parasharrajat Jan 8, 2022
a491cf4
Correct transfer amount format
parasharrajat Jan 8, 2022
9d8207c
added Fee consts
parasharrajat Jan 11, 2022
e46e185
Added fee calculations
parasharrajat Jan 11, 2022
0cea1a9
correct Confirmation Modal
parasharrajat Jan 11, 2022
6e3df64
correct fee calculations
parasharrajat Jan 11, 2022
4883344
Merge branch 'main' of github.com:Expensify/Expensify.cash into trans…
parasharrajat Jan 11, 2022
f09a386
fix missing types and imports
parasharrajat Jan 11, 2022
f3f30ef
Fix Instant transfer Rate
parasharrajat Jan 11, 2022
b51397e
correct translations and naming
parasharrajat Jan 12, 2022
3e44bc0
fix: imports and checks
parasharrajat Jan 12, 2022
0782a10
translations
parasharrajat Jan 12, 2022
efeb43c
Refactor and cleanup
parasharrajat Jan 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,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 @@ -462,6 +471,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 @@ -353,7 +353,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 @@ -353,7 +353,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});
}
Comment thread
parasharrajat marked this conversation as resolved.

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
Comment thread
stitesExpensify marked this conversation as resolved.
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