Skip to content

Commit

Permalink
Merge pull request #47218 from rezkiy37/feature/45177-invoice-back-ac…
Browse files Browse the repository at this point in the history
…counts-section

Invoicing bank accounts section
  • Loading branch information
madmax330 authored Sep 30, 2024
2 parents 8636074 + 2ffc83e commit 0e7d707
Show file tree
Hide file tree
Showing 13 changed files with 441 additions and 109 deletions.
28 changes: 28 additions & 0 deletions src/hooks/usePaymentMethodState/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {useCallback, useState} from 'react';
import type {PaymentMethodState} from './types';

const initialState: PaymentMethodState = {
isSelectedPaymentMethodDefault: false,
selectedPaymentMethod: {},
formattedSelectedPaymentMethod: {
title: '',
},
methodID: '',
selectedPaymentMethodType: '',
};

function usePaymentMethodState() {
const [paymentMethod, setPaymentMethod] = useState<PaymentMethodState>(initialState);

const resetSelectedPaymentMethodData = useCallback(() => {
setPaymentMethod(initialState);
}, [setPaymentMethod]);

return {
paymentMethod,
setPaymentMethod,
resetSelectedPaymentMethodData,
};
}

export default usePaymentMethodState;
28 changes: 28 additions & 0 deletions src/hooks/usePaymentMethodState/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type {ViewStyle} from 'react-native';
import type {AccountData} from '@src/types/onyx';
import type IconAsset from '@src/types/utils/IconAsset';

type FormattedSelectedPaymentMethodIcon = {
icon: IconAsset;
iconHeight?: number;
iconWidth?: number;
iconStyles?: ViewStyle[];
iconSize?: number;
};

type FormattedSelectedPaymentMethod = {
title: string;
icon?: FormattedSelectedPaymentMethodIcon;
description?: string;
type?: string;
};

type PaymentMethodState = {
isSelectedPaymentMethodDefault: boolean;
selectedPaymentMethod: AccountData;
formattedSelectedPaymentMethod: FormattedSelectedPaymentMethod;
methodID: string | number;
selectedPaymentMethodType: string;
};

export type {FormattedSelectedPaymentMethodIcon, FormattedSelectedPaymentMethod, PaymentMethodState};
3 changes: 2 additions & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ const translations = {
filterLogs: 'Filter Logs',
network: 'Network',
reportID: 'Report ID',
bankAccounts: 'Bank accounts',
chooseFile: 'Choose file',
dropTitle: 'Let it go',
dropMessage: 'Drop your file here',
Expand Down Expand Up @@ -1373,7 +1374,6 @@ const translations = {
enableWalletToSendAndReceiveMoney: 'Enable your wallet to send and receive money with friends.',
walletEnabledToSendAndReceiveMoney: 'Your wallet has been enabled to send and receive money with friends.',
enableWallet: 'Enable wallet',
bankAccounts: 'Bank accounts',
addBankAccountToSendAndReceive: 'Adding a bank account allows you to get paid back for expenses you submit to a workspace.',
addBankAccount: 'Add bank account',
assignedCards: 'Assigned cards',
Expand Down Expand Up @@ -3649,6 +3649,7 @@ const translations = {
payingAsIndividual: 'Paying as an individual',
payingAsBusiness: 'Paying as a business',
},
bankAccountsSubtitle: 'Add a bank account to receive invoice payments.',
},
invite: {
member: 'Invite member',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ const translations = {
filterLogs: 'Registros de filtrado',
network: 'La red',
reportID: 'ID del informe',
bankAccounts: 'Cuentas bancarias',
chooseFile: 'Elegir archivo',
dropTitle: 'Suéltalo',
dropMessage: 'Suelta tu archivo aquí',
Expand Down Expand Up @@ -1370,7 +1371,6 @@ const translations = {
enableWalletToSendAndReceiveMoney: 'Habilita tu Billetera Expensify para comenzar a enviar y recibir dinero con amigos.',
walletEnabledToSendAndReceiveMoney: 'Tu billetera ha sido habilitada para enviar y recibir dinero con amigos.',
enableWallet: 'Habilitar billetera',
bankAccounts: 'Cuentas bancarias',
addBankAccountToSendAndReceive: 'Agregar una cuenta bancaria te permite recibir reembolsos por los gastos que envíes a un espacio de trabajo.',
addBankAccount: 'Añadir cuenta bancaria',
assignedCards: 'Tarjetas asignadas',
Expand Down Expand Up @@ -3690,6 +3690,7 @@ const translations = {
payingAsIndividual: 'Pago individual',
payingAsBusiness: 'Pagar como una empresa',
},
bankAccountsSubtitle: 'Agrega una cuenta bancaria para recibir pagos de facturas.',
},
invite: {
member: 'Invitar miembros',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type SetInvoicingTransferBankAccountParams = {
bankAccountID: number;
policyID: string;
};

export default SetInvoicingTransferBankAccountParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,4 @@ export type {default as UpdateCompanyCard} from './UpdateCompanyCard';
export type {default as UpdateCompanyCardNameParams} from './UpdateCompanyCardNameParams';
export type {default as SetCompanyCardExportAccountParams} from './SetCompanyCardExportAccountParams';
export type {default as SetMissingPersonalDetailsAndShipExpensifyCardParams} from './SetMissingPersonalDetailsAndShipExpensifyCardParams';
export type {default as SetInvoicingTransferBankAccountParams} from './SetInvoicingTransferBankAccountParams';
3 changes: 3 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ const WRITE_COMMANDS = {
UPDATE_COMPANY_CARD_NAME: 'SetCardName',
SET_CARD_EXPORT_ACCOUNT: 'SetCardExportAccount',
SET_MISSING_PERSONAL_DETAILS_AND_SHIP_EXPENSIFY_CARD: 'SetMissingPersonalDetailsAndShipExpensifyCard',
SET_INVOICING_TRANSFER_BANK_ACCOUNT: 'SetInvoicingTransferBankAccount',
} as const;

type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
Expand Down Expand Up @@ -825,6 +826,8 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.UPDATE_XERO_SYNC_INVOICE_COLLECTIONS_ACCOUNT_ID]: Parameters.UpdateXeroGenericTypeParams;
[WRITE_COMMANDS.UPDATE_XERO_SYNC_SYNC_REIMBURSED_REPORTS]: Parameters.UpdateXeroGenericTypeParams;
[WRITE_COMMANDS.UPDATE_XERO_SYNC_REIMBURSEMENT_ACCOUNT_ID]: Parameters.UpdateXeroGenericTypeParams;

[WRITE_COMMANDS.SET_INVOICING_TRANSFER_BANK_ACCOUNT]: Parameters.SetInvoicingTransferBankAccountParams;
};

const READ_COMMANDS = {
Expand Down
46 changes: 46 additions & 0 deletions src/libs/actions/PaymentMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
DeletePaymentCardParams,
MakeDefaultPaymentMethodParams,
PaymentCardParams,
SetInvoicingTransferBankAccountParams,
TransferWalletBalanceParams,
UpdateBillingCurrencyParams,
} from '@libs/API/parameters';
Expand Down Expand Up @@ -531,6 +532,50 @@ function setPaymentCardForm(values: AccountData) {
});
}

/**
* Sets the default bank account to use for receiving payouts from
*
*/
function setInvoicingTransferBankAccount(bankAccountID: number, policyID: string, previousBankAccountID: number) {
const parameters: SetInvoicingTransferBankAccountParams = {
bankAccountID,
policyID,
};

const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
invoice: {
bankAccount: {
transferBankAccountID: bankAccountID,
},
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
invoice: {
bankAccount: {
transferBankAccountID: previousBankAccountID,
},
},
},
},
];

API.write(WRITE_COMMANDS.SET_INVOICING_TRANSFER_BANK_ACCOUNT, parameters, {
optimisticData,
failureData,
});
}

export {
deletePaymentCard,
addPaymentCard,
Expand All @@ -555,4 +600,5 @@ export {
clearWalletTermsError,
setPaymentCardForm,
verifySetupIntent,
setInvoicingTransferBankAccount,
};
98 changes: 46 additions & 52 deletions src/pages/settings/Wallet/PaymentMethodList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import type {ReactElement, Ref} from 'react';
import React, {useCallback, useMemo} from 'react';
import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native';
import {FlatList, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import type {SvgProps} from 'react-native-svg/lib/typescript/ReactNativeSVG';
import type {ValueOf} from 'type-fest';
import type {RenderSuggestionMenuItemProps} from '@components/AutoCompleteSuggestions/types';
Expand All @@ -18,6 +17,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import type {FormattedSelectedPaymentMethodIcon} from '@hooks/usePaymentMethodState/types';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CardUtils from '@libs/CardUtils';
Expand All @@ -30,29 +30,14 @@ import * as PaymentMethods from '@userActions/PaymentMethods';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {AccountData, BankAccountList, CardList} from '@src/types/onyx';
import type {AccountData} from '@src/types/onyx';
import type {BankIcon} from '@src/types/onyx/Bank';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import type PaymentMethod from '@src/types/onyx/PaymentMethod';
import type {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {FormattedSelectedPaymentMethodIcon} from './WalletPage/types';

type PaymentMethodListOnyxProps = {
/** List of bank accounts */
bankAccountList: OnyxEntry<BankAccountList>;

/** List of assigned cards */
cardList: OnyxEntry<CardList>;

/** List of user's cards */
// fundList: OnyxEntry<FundList>;

/** Are we loading payment methods? */
isLoadingPaymentMethods: OnyxEntry<boolean>;
};

type PaymentMethodListProps = PaymentMethodListOnyxProps & {
type PaymentMethodListProps = {
/** Type of active/highlighted payment method */
actionPaymentMethodType?: string;

Expand Down Expand Up @@ -92,6 +77,9 @@ type PaymentMethodListProps = PaymentMethodListOnyxProps & {
/** Whether the add Payment button be shown on the list */
shouldShowAddPaymentMethodButton?: boolean;

/** Whether the add Bank account button be shown on the list */
shouldShowAddBankAccountButton?: boolean;

/** Whether the assigned cards should be shown on the list */
shouldShowAssignedCards?: boolean;

Expand All @@ -110,6 +98,9 @@ type PaymentMethodListProps = PaymentMethodListOnyxProps & {
isDefault?: boolean,
methodID?: number,
) => void;

/** The policy invoice's transfer bank accountID */
invoiceTransferBankAccountID?: number;
};

type PaymentMethodItem = PaymentMethod & {
Expand Down Expand Up @@ -173,17 +164,13 @@ function keyExtractor(item: PaymentMethod) {
function PaymentMethodList({
actionPaymentMethodType = '',
activePaymentMethodID = '',
bankAccountList = {},
buttonRef = () => {},
cardList = {},
// Temporarily disabled because P2P debit cards are disabled.
// fundList = {},
filterType = '',
listHeaderComponent,
isLoadingPaymentMethods = true,
onPress,
shouldShowSelectedState = false,
shouldShowAddPaymentMethodButton = true,
shouldShowAddBankAccountButton = false,
shouldShowAddBankAccount = true,
shouldShowEmptyListMessage = true,
shouldShowAssignedCards = false,
Expand All @@ -193,12 +180,18 @@ function PaymentMethodList({
style = {},
listItemStyle = {},
shouldShowRightIcon = true,
invoiceTransferBankAccountID,
}: PaymentMethodListProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated});
const [bankAccountList = {}] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST);
// Temporarily disabled because P2P debit cards are disabled.
// const [fundList = {}] = useOnyx(ONYXKEYS.FUND_LIST);
const [isLoadingPaymentMethods = true] = useOnyx(ONYXKEYS.IS_LOADING_PAYMENT_METHODS);

const getDescriptionForPolicyDomainCard = (domainName: string): string => {
// A domain name containing a policyID indicates that this is a workspace feed
Expand Down Expand Up @@ -324,18 +317,29 @@ function PaymentMethodList({
const renderListEmptyComponent = () => <Text style={styles.popoverMenuItem}>{translate('paymentMethodList.addFirstPaymentMethod')}</Text>;

const renderListFooterComponent = useCallback(
() => (
<MenuItem
onPress={onPress}
title={translate('walletPage.addBankAccount')}
icon={Expensicons.Plus}
wrapperStyle={[styles.paymentMethod, listItemStyle]}
ref={buttonRef}
disabled={!isUserValidated}
/>
),
() =>
shouldShowAddBankAccountButton ? (
<Button
ref={buttonRef}
key="addBankAccountButton"
text={translate('walletPage.addBankAccount')}
large
success
isDisabled={!isUserValidated}
onPress={onPress}
/>
) : (
<MenuItem
onPress={onPress}
title={translate('walletPage.addBankAccount')}
icon={Expensicons.Plus}
wrapperStyle={[styles.paymentMethod, listItemStyle]}
ref={buttonRef}
disabled={!isUserValidated}
/>
),

[onPress, translate, styles.paymentMethod, listItemStyle, buttonRef, isUserValidated],
[shouldShowAddBankAccountButton, translate, onPress, buttonRef, styles.paymentMethod, listItemStyle, isUserValidated],
);

/**
Expand All @@ -360,7 +364,11 @@ function PaymentMethodList({
iconHeight={item.iconHeight ?? item.iconSize}
iconWidth={item.iconWidth ?? item.iconSize}
iconStyles={item.iconStyles}
badgeText={shouldShowDefaultBadge(filteredPaymentMethods, item.isDefault) ? translate('paymentMethodList.defaultPaymentMethod') : undefined}
badgeText={
shouldShowDefaultBadge(filteredPaymentMethods, invoiceTransferBankAccountID ? invoiceTransferBankAccountID === item.methodID : item.isDefault)
? translate('paymentMethodList.defaultPaymentMethod')
: undefined
}
wrapperStyle={[styles.paymentMethod, listItemStyle]}
iconRight={item.iconRight}
badgeStyle={styles.badgeBordered}
Expand All @@ -374,7 +382,7 @@ function PaymentMethodList({
</OfflineWithFeedback>
),

[styles.ph6, styles.paymentMethod, styles.badgeBordered, filteredPaymentMethods, translate, listItemStyle, shouldShowSelectedState, selectedMethodID],
[styles.ph6, styles.paymentMethod, styles.badgeBordered, filteredPaymentMethods, invoiceTransferBankAccountID, translate, listItemStyle, shouldShowSelectedState, selectedMethodID],
);

return (
Expand Down Expand Up @@ -416,18 +424,4 @@ function PaymentMethodList({

PaymentMethodList.displayName = 'PaymentMethodList';

export default withOnyx<PaymentMethodListProps, PaymentMethodListOnyxProps>({
bankAccountList: {
key: ONYXKEYS.BANK_ACCOUNT_LIST,
},
cardList: {
key: ONYXKEYS.CARD_LIST,
},
// Temporarily disabled - used for P2P debit cards
// fundList: {
// key: ONYXKEYS.FUND_LIST,
// },
isLoadingPaymentMethods: {
key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS,
},
})(PaymentMethodList);
export default PaymentMethodList;
Loading

0 comments on commit 0e7d707

Please sign in to comment.