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

feat: new riverty component #2532

Merged
merged 12 commits into from
Feb 19, 2024
5 changes: 5 additions & 0 deletions .changeset/healthy-bulldogs-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@adyen/adyen-web": minor
---

Add the support for new Riverty component. It will replace the old AfterPay component in the future, currently only supports AT, CH and DE countries.
8 changes: 4 additions & 4 deletions packages/lib/src/components/AfterPay/AfterPay.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { h } from 'preact';
import OpenInvoiceContainer from '../helpers/OpenInvoiceContainer';
import ConsentCheckboxLabel from './components/ConsentCheckboxLabel';
import { getConsentLinkUrl } from './utils';
import { ALLOWED_COUNTRIES } from './config';
import ConsentCheckboxLabel from '../internal/ConsentCheckboxLabel';
import { ALLOWED_COUNTRIES, rivertyConsentUrlMap } from './config';
import { getConsentUrl } from '../../utils/getConsentUrl';

export default class AfterPay extends OpenInvoiceContainer {
public static type = 'afterpay_default';
Expand All @@ -11,7 +11,7 @@ export default class AfterPay extends OpenInvoiceContainer {
return {
...super.formatProps(props),
allowedCountries: props.countryCode ? [props.countryCode] : ALLOWED_COUNTRIES,
consentCheckboxLabel: <ConsentCheckboxLabel url={getConsentLinkUrl(props.countryCode, props.i18n?.locale)} />
consentCheckboxLabel: <ConsentCheckboxLabel url={getConsentUrl(props.countryCode, props.i18n?.locale, rivertyConsentUrlMap)} />
};
}
}
41 changes: 0 additions & 41 deletions packages/lib/src/components/AfterPay/utils.test.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/lib/src/components/AfterPay/utils.ts

This file was deleted.

115 changes: 115 additions & 0 deletions packages/lib/src/components/Riverty/Riverty.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { h } from 'preact';
import Riverty from './Riverty';
import { render, screen } from '@testing-library/preact';
import { Resources } from '../../core/Context/Resources';
import { SRPanel } from '../../core/Errors/SRPanel';
import Language from '../../language';
import getDataset from '../../core/Services/get-dataset';
import { termsAndConditionsUrlMap } from './config';
import { OpenInvoiceContainerProps } from '../helpers/OpenInvoiceContainer/OpenInvoiceContainer';

jest.mock('../../core/Services/get-dataset');
const countriesMock = [
{
id: 'DE',
name: 'Germany'
}
];

(getDataset as jest.Mock).mockImplementation(jest.fn(() => Promise.resolve(countriesMock)));

describe('Riverty', () => {
const props: OpenInvoiceContainerProps = {
i18n: new Language(),
loadingContext: 'test',
countryCode: 'DE',
modules: {
resources: new Resources('test'),
srPanel: new SRPanel({})
}
};

describe('personal details', () => {
test('should show required fields', async () => {
// @ts-ignore ignore
render(<Riverty {...props} />);
const firstName = await screen.findByLabelText('First name', { selector: 'input' });
const lastName = await screen.findByLabelText('Last name', { selector: 'input' });
const dateOfBirth = await screen.findByLabelText('Date of birth', { selector: 'input' });
const email = await screen.findByLabelText('Email address', { selector: 'input' });
const telephone = await screen.findByLabelText('Telephone number', { selector: 'input' });
const male = screen.queryByLabelText('Male');
const female = screen.queryByLabelText('Female');

expect(firstName).not.toBeNull();
expect(lastName).not.toBeNull();
expect(dateOfBirth).not.toBeNull();
expect(email).not.toBeNull();
expect(telephone).not.toBeNull();
expect(male).toBeNull();
expect(female).toBeNull();
});
});

describe('delivery address', () => {
test('should show required fields', async () => {
const withDeliveryAddressData = {
...props,
data: {
deliveryAddress: {
firstName: 'First',
lastName: 'Last'
}
}
};
// @ts-ignore ignore
render(<Riverty {...withDeliveryAddressData} />);
const firstName = await screen.findByLabelText('Recipient first name', { selector: 'input' });
const lastName = await screen.findByLabelText('Recipient last name', { selector: 'input' });
const country = await screen.findAllByLabelText('Country');
const street = await screen.findAllByLabelText('Street');
const houseNumber = await screen.findAllByLabelText('House number');
const postalCode = await screen.findAllByLabelText('Postal code');
const city = await screen.findAllByLabelText('City');
expect(firstName).not.toBeNull();
expect(lastName).not.toBeNull();
expect(country.length).toBe(2);
expect(street.length).toBe(2);
expect(houseNumber.length).toBe(2);
expect(postalCode.length).toBe(2);
expect(city.length).toBe(2);
});

test('should show the correct read-only fields', async () => {
const withReadOnlyDeliveryAddressData: OpenInvoiceContainerProps = {
...props,
visibility: {
deliveryAddress: 'readOnly'
},
data: {
deliveryAddress: {
firstName: 'dummy first name',
lastName: 'dummy last name',
street: 'dummy street',
houseNumberOrName: 'dummy houseNumberOrName',
city: 'dummy city'
}
}
};

render(new Riverty(withReadOnlyDeliveryAddressData).render());
for (const value of Object.values(withReadOnlyDeliveryAddressData.data.deliveryAddress)) {
const element = await screen.findByText(new RegExp(value), { exact: false });
expect(element).toBeInTheDocument();
}
});
});

describe('terms and conditions', () => {
test('should show the correct t&c urls', async () => {
render(new Riverty(props).render());
const tcLink = await screen.findByRole('link', { name: 'payment conditions' });
expect(tcLink).toHaveAttribute('href', termsAndConditionsUrlMap[props.countryCode.toLowerCase()].en);
});
});
});
34 changes: 34 additions & 0 deletions packages/lib/src/components/Riverty/Riverty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { h } from 'preact';
import OpenInvoiceContainer from '../helpers/OpenInvoiceContainer';
import {
allowedBillingCountries,
allowedDeliveryCountries,
deliveryAddressSpecification,
personalDetailsRequiredFields,
termsAndConditionsUrlMap
} from './config';
import ConsentCheckboxLabel from '../internal/ConsentCheckboxLabel';
import { getConsentUrl } from '../../utils/getConsentUrl';
import { OpenInvoiceContainerProps } from '../helpers/OpenInvoiceContainer/OpenInvoiceContainer';

export default class Riverty extends OpenInvoiceContainer {
public static readonly type = 'riverty';

protected static defaultProps = {
personalDetailsRequiredFields,
deliveryAddressSpecification,
...OpenInvoiceContainer.defaultProps
};

formatProps(props: OpenInvoiceContainerProps) {
return {
...super.formatProps(props),
billingAddressSpecification: {
...props.billingAddressSpecification,
allowedCountries: props.countryCode ? [props.countryCode] : allowedBillingCountries
},
deliveryAddressSpecification: { ...props.deliveryAddressSpecification, allowedCountries: allowedDeliveryCountries },
consentCheckboxLabel: <ConsentCheckboxLabel url={getConsentUrl(props.countryCode, props.i18n?.locale, termsAndConditionsUrlMap)} />
};
}
}
45 changes: 45 additions & 0 deletions packages/lib/src/components/Riverty/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { CITY, COUNTRY, FIRST_NAME, HOUSE_NUMBER_OR_NAME, LAST_NAME, POSTAL_CODE, STREET } from '../internal/Address/constants';
import { AddressSpecifications } from '../internal/Address/types';

export const allowedBillingCountries = ['AT', 'CH', 'DE'];
export const allowedDeliveryCountries = ['NO', 'SE', 'FI', 'DK', 'DE', 'AT', 'CH', 'NL', 'BE'];
export const personalDetailsRequiredFields = ['firstName', 'lastName', 'dateOfBirth', 'shopperEmail', 'telephoneNumber'];
export const deliveryAddressSpecification: AddressSpecifications = {
default: {
labels: {
[FIRST_NAME]: 'deliveryAddress.firstName',
[LAST_NAME]: 'deliveryAddress.lastName'
},
schema: [
COUNTRY,
[
[FIRST_NAME, 50],
[LAST_NAME, 50]
],
[
[STREET, 70],
[HOUSE_NUMBER_OR_NAME, 30]
],

[
[POSTAL_CODE, 30],
[CITY, 70]
]
]
}
};
export const termsAndConditionsUrlMap = {
at: {
en: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/at_en',
de: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/at_de'
},
ch: {
en: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/ch_en',
de: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/ch_de',
fr: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/ch_fr'
},
de: {
en: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/de_en',
de: 'https://documents.riverty.com/terms_conditions/payment_methods/invoice/de_de'
}
};
1 change: 1 addition & 0 deletions packages/lib/src/components/Riverty/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Riverty';
2 changes: 2 additions & 0 deletions packages/lib/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import Duitnow from './DuitNow';
import ANCV from './ANCV';
import Trustly from './Trustly';
import PayMe from './PayMe';
import Riverty from './Riverty';

/**
* Maps each component with a Component element.
Expand Down Expand Up @@ -113,6 +114,7 @@ const componentsMap = {
facilypay_12x: FacilyPay12x,
ratepay: RatePay,
ratepay_directdebit: RatePayDirectDebit,
riverty: Riverty,
/** Open Invoice */

/** Wallets */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import { h } from 'preact';
import { Fragment, h } from 'preact';
import Fieldset from '../../FormFields/Fieldset';
import { ReadOnlyAddressProps } from '../types';
import { FALLBACK_VALUE } from '../constants';

const FullName = ({ firstName, lastName }) => {
return (
<Fragment>
{firstName && `${firstName} `}
{lastName && `${lastName}`}
<br />
</Fragment>
);
};

const ReadOnlyAddress = ({ data, label }: ReadOnlyAddressProps) => {
const { street, houseNumberOrName, city, postalCode, stateOrProvince, country } = data;
const { street, houseNumberOrName, city, postalCode, stateOrProvince, country, firstName, lastName } = data;
const hasName = firstName || lastName;

return (
<Fieldset classNameModifiers={[label]} label={label} readonly>
{hasName && <FullName firstName={firstName} lastName={lastName}></FullName>}
{!!street && street}
{houseNumberOrName && `, ${houseNumberOrName},`}
<br />
Expand Down
5 changes: 2 additions & 3 deletions packages/lib/src/components/internal/Address/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { AddressSpecifications } from './types';

export const FALLBACK_VALUE = 'N/A';
export const ADDRESS_SCHEMA = ['street', 'houseNumberOrName', 'postalCode', 'city', 'stateOrProvince', 'country'] as const;
export const [STREET, HOUSE_NUMBER_OR_NAME, POSTAL_CODE, CITY, STATE_OR_PROVINCE, COUNTRY] = ADDRESS_SCHEMA;

export const ADDRESS_SCHEMA = ['street', 'houseNumberOrName', 'postalCode', 'city', 'stateOrProvince', 'country', 'firstName', 'lastName'] as const;
export const [STREET, HOUSE_NUMBER_OR_NAME, POSTAL_CODE, CITY, STATE_OR_PROVINCE, COUNTRY, FIRST_NAME, LAST_NAME] = ADDRESS_SCHEMA;
// prettier-ignore
export const ADDRESS_SPECIFICATIONS: AddressSpecifications = {
AU: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Fragment, h } from 'preact';
import useCoreContext from '../../../../core/Context/useCoreContext';
import useCoreContext from '../../../core/Context/useCoreContext';

interface ConsentCheckboxLabelProps {
url: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ export default function OpenInvoice(props: OpenInvoiceProps) {
setValid(prevValid => ({ ...prevValid, consentCheckbox: checked }));
setErrors(prevErrors => ({ ...prevErrors, consentCheckbox: !checked }));
};

return (
<div className="adyen-checkout__open-invoice">
{props.showFormInstruction && <FormInstruction />}
Expand Down Expand Up @@ -271,7 +270,7 @@ export default function OpenInvoice(props: OpenInvoiceProps) {

{activeFieldsets.billingAddress && (
<Address
allowedCountries={props.allowedCountries}
allowedCountries={props?.billingAddressSpecification?.allowedCountries ?? props.allowedCountries}
countryCode={countryCode}
requiredFields={props.billingAddressRequiredFields}
specifications={props.billingAddressSpecification}
Expand All @@ -297,8 +296,10 @@ export default function OpenInvoice(props: OpenInvoiceProps) {

{activeFieldsets.deliveryAddress && (
<Address
allowedCountries={props.allowedCountries}
allowedCountries={props?.deliveryAddressSpecification?.allowedCountries ?? props.allowedCountries}
countryCode={countryCode}
requiredFields={props.deliveryAddressRequiredFields}
specifications={props.deliveryAddressSpecification}
longyulongyu marked this conversation as resolved.
Show resolved Hide resolved
data={data.deliveryAddress}
label="deliveryAddress"
onChange={handleFieldset('deliveryAddress')}
Expand Down
6 changes: 5 additions & 1 deletion packages/lib/src/components/internal/OpenInvoice/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { UIElementProps } from '../../types';
import UIElement from '../../UIElement';
import { GenericError, ValidationRuleErrorObj } from '../../../core/Errors/types';

type OpenInvoiceAddressSpecification = AddressSpecifications & { allowedCountries?: string[] };

export interface OpenInvoiceVisibility {
companyDetails?: FieldsetVisibility;
personalDetails?: FieldsetVisibility;
Expand Down Expand Up @@ -36,7 +38,9 @@ export interface OpenInvoiceProps extends UIElementProps {
visibility?: OpenInvoiceVisibility;
personalDetailsRequiredFields?: string[];
billingAddressRequiredFields?: string[];
billingAddressSpecification?: AddressSpecifications;
billingAddressSpecification?: OpenInvoiceAddressSpecification;
deliveryAddressRequiredFields?: string[];
deliveryAddressSpecification?: OpenInvoiceAddressSpecification;
setComponentRef?: (ref) => void;
showFormInstruction?: boolean;
}
Expand Down
Loading
Loading