Skip to content

Commit

Permalink
fix: onboarding currency messaging for BNPLs (#8202)
Browse files Browse the repository at this point in the history
Co-authored-by: Guilherme Pressutto <[email protected]>
  • Loading branch information
frosso and gpressutto5 authored Feb 16, 2024
1 parent bfbfbba commit aff086e
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 72 deletions.
4 changes: 4 additions & 0 deletions changelog/fix-onboarding-currency-messaging
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

fix: onboarding currency messaging for BNPLs
169 changes: 98 additions & 71 deletions client/components/currency-information-for-methods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import interpolateComponents from '@automattic/interpolate-components';
/**
* Internal dependencies
*/
import { useCurrencies, useEnabledCurrencies } from '../../data';
import {
useAccountDomesticCurrency,
useCurrencies,
useEnabledCurrencies,
} from '../../data';
import WCPaySettingsContext from '../../settings/wcpay-settings-context';
import InlineNotice from 'components/inline-notice';
import PaymentMethodsMap from '../../payment-methods-map';
Expand Down Expand Up @@ -62,6 +66,7 @@ const CurrencyInformationForMethods = ( { selectedMethods } ) => {
currencies: currencyInfo,
} = useCurrencies();
const { enabledCurrencies } = useEnabledCurrencies();
const stripeAccountDomesticCurrency = useAccountDomesticCurrency().toUpperCase();

if ( isLoadingCurrencyInformation ) {
return null;
Expand All @@ -73,86 +78,108 @@ const CurrencyInformationForMethods = ( { selectedMethods } ) => {

let paymentMethodsWithMissingCurrencies = [];
let missingCurrencyLabels = [];
const missingCurrencies = [];

selectedMethods.map( ( paymentMethod ) => {
if ( typeof PaymentMethodsMap[ paymentMethod ] !== 'undefined' ) {
PaymentMethodsMap[ paymentMethod ].currencies.map( ( currency ) => {
if (
! enabledCurrenciesIds.includes( currency.toLowerCase() )
) {
missingCurrencies.push( currency );

paymentMethodsWithMissingCurrencies.push(
PaymentMethodsMap[ paymentMethod ].label
);

const missingCurrencyInfo =
currencyInfo &&
currencyInfo.available &&
currencyInfo.available[ currency ];

const missingCurrencyLabel =
missingCurrencyInfo != null
? missingCurrencyInfo.name +
' (' +
( undefined !== missingCurrencyInfo.symbol
? missingCurrencyInfo.symbol
: currency.toUpperCase() ) +
')'
: currency.toUpperCase();

missingCurrencyLabels.push( missingCurrencyLabel );
}
return currency;
} );

selectedMethods.forEach( ( paymentMethod ) => {
// in case of payment methods accepting only domestic payments, we shouldn't add _all_ the currencies defined on the payment method.
// instead, we should ensure that the merchant account's currency is set.
const paymentMethodInformation = PaymentMethodsMap[ paymentMethod ];
if ( ! paymentMethodInformation ) return;

let currencies = paymentMethodInformation.currencies || [];
if ( paymentMethodInformation.accepts_only_domestic_payment ) {
currencies = [ stripeAccountDomesticCurrency ];
}
return paymentMethod;

currencies.forEach( ( currency ) => {
if ( enabledCurrenciesIds.includes( currency.toLowerCase() ) ) {
return;
}

paymentMethodsWithMissingCurrencies.push(
paymentMethodInformation.label
);
const missingCurrencyInfo = currencyInfo?.available?.[ currency ];

const missingCurrencyLabel =
missingCurrencyInfo != null
? `${ missingCurrencyInfo.name } (${
undefined !== missingCurrencyInfo.symbol
? missingCurrencyInfo.symbol
: currency.toUpperCase()
})`
: currency.toUpperCase();

missingCurrencyLabels.push( missingCurrencyLabel );
} );
} );

missingCurrencyLabels = _.uniq( missingCurrencyLabels );
paymentMethodsWithMissingCurrencies = _.uniq(
paymentMethodsWithMissingCurrencies
);

if ( missingCurrencyLabels.length > 0 ) {
return (
<InlineNotice icon status="info" isDismissible={ false }>
{ interpolateComponents( {
mixedString: sprintf(
__(
"%s %s %s additional %s, so {{strong}}we'll add %s to your store{{/strong}}. " +
'You can view & manage currencies later in settings.',
'woocommerce-payments'
),
ListToCommaSeparatedSentencePartConverter(
paymentMethodsWithMissingCurrencies
),
_n(
'requires',
'require',
paymentMethodsWithMissingCurrencies.length,
'woocommerce-payments'
),
missingCurrencyLabels.length === 1 ? 'an' : '',
_n(
'currency',
'currencies',
missingCurrencyLabels.length,
'woocommerce-payments'
),
ListToCommaSeparatedSentencePartConverter(
missingCurrencyLabels
)
),
components: {
strong: <strong />,
},
} ) }
</InlineNotice>
if ( missingCurrencyLabels.length <= 0 ) {
return null;
}

let stringFormat = '';
if (
paymentMethodsWithMissingCurrencies.length === 1 &&
missingCurrencyLabels.length === 1
) {
stringFormat = __(
/* translators: %1: name of payment method being setup %2: name of missing currency that will be added */
"%1$s requires an additional currency, so {{strong}}we'll add %2$s to your store{{/strong}}. " +
'You can view & manage currencies later in settings.',
'woocommerce-payments'
);
} else if (
paymentMethodsWithMissingCurrencies.length === 1 &&
missingCurrencyLabels.length > 1
) {
stringFormat = __(
/* translators: %1: name of payment method being setup %2: list of missing currencies that will be added */
"%1$s requires additional currencies, so {{strong}}we'll add %2$s to your store{{/strong}}. " +
'You can view & manage currencies later in settings.',
'woocommerce-payments'
);
} else if (
paymentMethodsWithMissingCurrencies.length > 1 &&
missingCurrencyLabels.length === 1
) {
stringFormat = __(
/* translators: %1: list of payment methods being setup %2: name of missing currency that will be added */
"%1$s require an additional currency, so {{strong}}we'll add %2$s to your store{{/strong}}. " +
'You can view & manage currencies later in settings.',
'woocommerce-payments'
);
} else {
stringFormat = __(
/* translators: %1: list of payment methods being setup %2: list of missing currencies that will be added */
"%1$s require additional currencies, so {{strong}}we'll add %2$s to your store{{/strong}}. " +
'You can view & manage currencies later in settings.',
'woocommerce-payments'
);
}
return null;

return (
<InlineNotice icon status="info" isDismissible={ false }>
{ interpolateComponents( {
mixedString: sprintf(
stringFormat,
ListToCommaSeparatedSentencePartConverter(
paymentMethodsWithMissingCurrencies
),
ListToCommaSeparatedSentencePartConverter(
missingCurrencyLabels
)
),
components: {
strong: <strong />,
},
} ) }
</InlineNotice>
);
};

const CurrencyInformationForMethodsWrapper = ( props ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { render, screen } from '@testing-library/react';
/**
* Internal dependencies
*/
import { useCurrencies, useEnabledCurrencies } from '../../../data';
import {
useCurrencies,
useEnabledCurrencies,
useAccountDomesticCurrency,
} from '../../../data';
import CurrencyInformationForMethods, {
BuildMissingCurrenciesTooltipMessage,
} from '..';
Expand All @@ -16,6 +20,7 @@ import WCPaySettingsContext from '../../../settings/wcpay-settings-context';
jest.mock( '../../../data', () => ( {
useCurrencies: jest.fn(),
useEnabledCurrencies: jest.fn(),
useAccountDomesticCurrency: jest.fn(),
} ) );

jest.mock( '@wordpress/a11y', () => ( {
Expand Down Expand Up @@ -48,6 +53,7 @@ describe( 'CurrencyInformationForMethods', () => {
USD: { id: 'usd', code: 'USD' },
},
} );
useAccountDomesticCurrency.mockReturnValue( 'usd' );
} );

it( 'should not display content when the feature flag is disabled', () => {
Expand Down Expand Up @@ -188,6 +194,51 @@ describe( 'CurrencyInformationForMethods', () => {
).toBeInTheDocument();
} );

it( "should not display a notice for additional currencies for BNPL methods, if the account's currency is already enabled", () => {
const { container } = render(
<FlagsContextWrapper>
<CurrencyInformationForMethods
selectedMethods={ [
'afterpay_clearpay',
'klarna',
'affirm',
] }
/>
</FlagsContextWrapper>
);

expect( container.firstChild ).toBeNull();
} );

it( "should display a notice to enable additional currencies for BNPL methods, if the account' currency is not enabled", () => {
useAccountDomesticCurrency.mockReturnValue( 'eur' );
render(
<FlagsContextWrapper>
<CurrencyInformationForMethods
selectedMethods={ [
'afterpay_clearpay',
'klarna',
'affirm',
] }
/>
</FlagsContextWrapper>
);

expect(
screen.queryByText(
/Afterpay, Klarna, and Affirm require an additional currency/,
{
ignore: '.a11y-speak-region',
}
)
).toBeInTheDocument();
expect(
screen.queryByText( /we\'ll add Euro \(€\) to your store/, {
ignore: '.a11y-speak-region',
} )
).toBeInTheDocument();
} );

it( 'returns correct string with the given LPM label and currency list', () => {
const output = BuildMissingCurrenciesTooltipMessage( 'x', [ 'EUR' ] );
expect( output ).toBe(
Expand Down
14 changes: 14 additions & 0 deletions client/payment-methods-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface PaymentMethodMapEntry {
stripe_key: string;
allows_manual_capture: boolean;
allows_pay_later: boolean;
accepts_only_domestic_payment: boolean;
}

const PaymentMethodInformationObject: Record<
Expand Down Expand Up @@ -73,6 +74,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'card_payments',
allows_manual_capture: true,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
au_becs_debit: {
id: 'au_becs_debit',
Expand All @@ -89,6 +91,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'au_becs_debit_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
bancontact: {
id: 'bancontact',
Expand All @@ -105,6 +108,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'bancontact_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
eps: {
id: 'eps',
Expand All @@ -121,6 +125,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'eps_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
giropay: {
id: 'giropay',
Expand All @@ -137,6 +142,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'giropay_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
ideal: {
id: 'ideal',
Expand All @@ -153,6 +159,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'ideal_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
p24: {
id: 'p24',
Expand All @@ -169,6 +176,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'p24_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
sepa_debit: {
id: 'sepa_debit',
Expand All @@ -185,6 +193,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'sepa_debit_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
sofort: {
id: 'sofort',
Expand All @@ -201,6 +210,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'sofort_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
affirm: {
id: 'affirm',
Expand All @@ -218,6 +228,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'affirm_payments',
allows_manual_capture: false,
allows_pay_later: true,
accepts_only_domestic_payment: true,
},
afterpay_clearpay: {
id: 'afterpay_clearpay',
Expand Down Expand Up @@ -248,6 +259,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'afterpay_clearpay_payments',
allows_manual_capture: false,
allows_pay_later: true,
accepts_only_domestic_payment: true,
},
jcb: {
id: 'jcb',
Expand All @@ -264,6 +276,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'jcb_payments',
allows_manual_capture: false,
allows_pay_later: false,
accepts_only_domestic_payment: false,
},
klarna: {
id: 'klarna',
Expand All @@ -281,6 +294,7 @@ const PaymentMethodInformationObject: Record<
stripe_key: 'klarna_payments',
allows_manual_capture: false,
allows_pay_later: true,
accepts_only_domestic_payment: true,
},
};

Expand Down

0 comments on commit aff086e

Please sign in to comment.