Skip to content
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

Invoicing bank accounts section #47218

Merged
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
67e37b9
create raw WorkspaceInvoiceVBASection
rezkiy37 Aug 12, 2024
c2b9af4
add invoice types
rezkiy37 Aug 12, 2024
077a401
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Aug 12, 2024
be90481
integrate bank accounts logic
rezkiy37 Aug 12, 2024
8e9d73e
add translations
rezkiy37 Aug 12, 2024
3661b67
integrate add bank account button
rezkiy37 Aug 12, 2024
e7a88a0
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Aug 13, 2024
97d6073
omit card logic
rezkiy37 Aug 13, 2024
54591c2
reuse types
rezkiy37 Aug 13, 2024
2a8f11f
integrate usePaymentMethodState hook
rezkiy37 Aug 13, 2024
cb90633
rename shouldUseSuccessAddBankAccountButton
rezkiy37 Aug 13, 2024
05af88f
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Aug 14, 2024
edd8507
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 2, 2024
2bec476
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 3, 2024
162d4da
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 9, 2024
c3258e2
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 12, 2024
68cb5a2
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 16, 2024
676a0da
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 24, 2024
8094a1a
implement setInvoicingTransferBankAccount
rezkiy37 Sep 25, 2024
6b2fff4
PaymentMethodList accepts invoiceTransferBankAccountID
rezkiy37 Sep 25, 2024
d273a5a
implement default back account in WorkspaceInvoiceVBASection
rezkiy37 Sep 25, 2024
46f5e1b
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 25, 2024
03b76f2
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 26, 2024
386dc9c
Refactor PaymentMethodList component to use useOnyx
rezkiy37 Sep 26, 2024
7b0f675
Merge branches 'feature/45177-invoice-back-accounts-section', 'featur…
rezkiy37 Sep 27, 2024
c8861f3
update disabled prop
rezkiy37 Sep 27, 2024
5ae1ca6
rename shouldShowAddBankAccountButton
rezkiy37 Sep 27, 2024
5635b84
tweak comment
rezkiy37 Sep 27, 2024
2ffc83e
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Sep 30, 2024
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
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 @@ -457,6 +457,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 @@ -1364,7 +1365,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 @@ -3634,6 +3634,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 @@ -449,6 +449,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 @@ -3684,6 +3684,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 or debit card for the Invoices
madmax330 marked this conversation as resolved.
Show resolved Hide resolved
*
*/
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);
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved
// Temporarily disabled because P2P debit cards are disabled.
// const [fundList = {}] = useOnyx(ONYXKEYS.FUND_LIST);
const [isLoadingPaymentMethods = true] = useOnyx(ONYXKEYS.IS_LOADING_PAYMENT_METHODS);
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved

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
Loading