diff --git a/packages/lib/src/components/ApplePay/components/ApplePayButton.module.scss b/packages/lib/src/components/ApplePay/components/ApplePayButton.module.scss index 9bd308e6e8..8573b7830a 100644 --- a/packages/lib/src/components/ApplePay/components/ApplePayButton.module.scss +++ b/packages/lib/src/components/ApplePay/components/ApplePayButton.module.scss @@ -1,7 +1,15 @@ @supports (-webkit-appearance: -apple-pay-button) { + + /* + * Combination of both classes improve the specificity, avoiding + * overwrite of the -webkit-appearence by the button native css + */ + .apple-pay, .apple-pay-button { - display: inline-block; -webkit-appearance: -apple-pay-button; + } + .apple-pay-button { + display: inline-block; cursor: pointer; } .apple-pay-button-black { @@ -13,7 +21,6 @@ .apple-pay-button-white-with-line { -apple-pay-button-style: white-outline; } - /* Apple Pay Button types https://developer.apple.com/documentation/apple_pay_on_the_web/displaying_apple_pay_buttons */ .apple-pay-button--type-plain { -apple-pay-button-type: plain; diff --git a/packages/lib/src/components/ApplePay/components/ApplePayButton.scss b/packages/lib/src/components/ApplePay/components/ApplePayButton.scss index 7bd590dbf3..22eb025147 100644 --- a/packages/lib/src/components/ApplePay/components/ApplePayButton.scss +++ b/packages/lib/src/components/ApplePay/components/ApplePayButton.scss @@ -1,6 +1,6 @@ .adyen-checkout__applepay__button { width: 240px; - height: 40px; + height: 48px; } .adyen-checkout__dropin .adyen-checkout__applepay__button { diff --git a/packages/lib/src/components/ApplePay/components/ApplePayButton.tsx b/packages/lib/src/components/ApplePay/components/ApplePayButton.tsx index ae3a84a1f1..a37e99e0d0 100644 --- a/packages/lib/src/components/ApplePay/components/ApplePayButton.tsx +++ b/packages/lib/src/components/ApplePay/components/ApplePayButton.tsx @@ -30,6 +30,7 @@ class ApplePayButton extends Component { 'adyen-checkout__applepay__button', `adyen-checkout__applepay__button--${buttonColor}`, `adyen-checkout__applepay__button--${buttonType}`, + [styles['apple-pay']], [styles['apple-pay-button']], [styles[`apple-pay-button-${buttonColor}`]], [styles[`apple-pay-button--type-${buttonType}`]] diff --git a/packages/lib/src/components/ApplePay/types.ts b/packages/lib/src/components/ApplePay/types.ts index 6201165a56..7110cd42de 100644 --- a/packages/lib/src/components/ApplePay/types.ts +++ b/packages/lib/src/components/ApplePay/types.ts @@ -41,13 +41,17 @@ export interface ApplePayElementProps extends UIElementProps { */ countryCode: string; + /** + * Part of the 'ApplePayLineItem' object, which sets the label of the payment request + * @see {@link https://developer.apple.com/documentation/apple_pay_on_the_web/applepaylineitem ApplePayLineItem docs} + */ + totalPriceLabel: string; + /** * @default 'final' */ totalPriceStatus?: ApplePayJS.ApplePayLineItemType; - totalPriceLabel?: string; - configuration: { merchantName?: string; merchantId?: string; diff --git a/packages/lib/src/components/BaseElement.ts b/packages/lib/src/components/BaseElement.ts index 6f5bc41598..5847ce83a9 100644 --- a/packages/lib/src/components/BaseElement.ts +++ b/packages/lib/src/components/BaseElement.ts @@ -1,4 +1,4 @@ -import { render } from 'preact'; +import { ComponentChild, render } from 'preact'; import getProp from '../utils/getProp'; import EventEmitter from './EventEmitter'; import uuid from '../utils/uuid'; @@ -60,7 +60,7 @@ class BaseElement

{ }; } - protected render() { + public render(): ComponentChild | Error { // render() not implemented in the element throw new Error('Payment method cannot be rendered.'); } diff --git a/packages/lib/src/components/Dropin/Dropin.test.ts b/packages/lib/src/components/Dropin/Dropin.test.ts index 81a7be3c8a..93a1674e4c 100644 --- a/packages/lib/src/components/Dropin/Dropin.test.ts +++ b/packages/lib/src/components/Dropin/Dropin.test.ts @@ -12,7 +12,7 @@ describe('Dropin', () => { beforeEach(() => { const checkout = new AdyenCheckout({}); - dropin = checkout.create('dropin', {}); + dropin = checkout.create('dropin'); }); describe('isValid', () => { @@ -80,7 +80,7 @@ describe('Dropin', () => { test('should handle new challenge action', () => { const checkout = new AdyenCheckout({}); - const dropin = checkout.create('dropin', {}); + const dropin = checkout.create('dropin'); const pa = dropin.handleAction(challengeAction); expect(pa.componentFromAction instanceof ThreeDS2Challenge).toEqual(true); @@ -112,4 +112,48 @@ describe('Dropin', () => { expect(pa.componentFromAction.props.challengeWindowSize).toEqual('03'); }); }); + + describe('Instant Payments feature', () => { + test('formatProps formats instantPaymentTypes removing duplicates and invalid values', () => { + const checkout = new AdyenCheckout({}); + // @ts-ignore + const dropin = checkout.create('dropin', { instantPaymentTypes: ['alipay', 'paywithgoogle', 'paywithgoogle', 'paypal'] }); + + expect(dropin.props.instantPaymentTypes).toStrictEqual(['paywithgoogle']); + }); + + test('formatProps filter out instantPaymentMethods from paymentMethods list ', () => { + const checkout = new AdyenCheckout({ + paymentMethodsResponse: { + paymentMethods: [ + { name: 'Google Pay', type: 'paywithgoogle' }, + { name: 'AliPay', type: 'alipay' } + ] + } + }); + const dropin = checkout.create('dropin', { instantPaymentTypes: ['paywithgoogle'] }); + + expect(dropin.props.paymentMethods).toHaveLength(1); + expect(dropin.props.paymentMethods[0]).toStrictEqual({ type: 'alipay', name: 'AliPay' }); + expect(dropin.props.instantPaymentMethods).toHaveLength(1); + expect(dropin.props.instantPaymentMethods[0]).toStrictEqual({ name: 'Google Pay', type: 'paywithgoogle' }); + }); + + test('formatProps does not change paymentMethods list if instantPaymentType is not provided', () => { + const paymentMethods = [ + { name: 'Google Pay', type: 'paywithgoogle' }, + { name: 'AliPay', type: 'alipay' } + ]; + + const checkout = new AdyenCheckout({ + paymentMethodsResponse: { + paymentMethods + } + }); + const dropin = checkout.create('dropin'); + + expect(dropin.props.paymentMethods).toStrictEqual(paymentMethods); + expect(dropin.props.instantPaymentMethods).toHaveLength(0); + }); + }); }); diff --git a/packages/lib/src/components/Dropin/Dropin.tsx b/packages/lib/src/components/Dropin/Dropin.tsx index 9f6a097b9f..575d24fae9 100644 --- a/packages/lib/src/components/Dropin/Dropin.tsx +++ b/packages/lib/src/components/Dropin/Dropin.tsx @@ -4,9 +4,12 @@ import defaultProps from './defaultProps'; import DropinComponent from '../../components/Dropin/components/DropinComponent'; import CoreProvider from '../../core/Context/CoreProvider'; import { PaymentAction } from '../../types'; -import { DropinElementProps } from './types'; +import { DropinElementProps, InstantPaymentTypes } from './types'; import { getCommonProps } from './components/utils'; import { createElements, createStoredElements } from './elements'; +import createInstantPaymentElements from './elements/createInstantPaymentElements'; + +const SUPPORTED_INSTANT_PAYMENTS = ['paywithgoogle', 'applepay']; class DropinElement extends UIElement { public static type = 'dropin'; @@ -19,6 +22,27 @@ class DropinElement extends UIElement { this.handleAction = this.handleAction.bind(this); } + formatProps(props) { + const instantPaymentTypes: InstantPaymentTypes[] = Array.from(new Set(props.instantPaymentTypes)).filter(value => + SUPPORTED_INSTANT_PAYMENTS.includes(value) + ); + + const instantPaymentMethods = instantPaymentTypes.reduce((memo, paymentType) => { + const paymentMethod = props.paymentMethods.find(({ type }) => type === paymentType); + if (paymentMethod) return [...memo, paymentMethod]; + return memo; + }, []); + + const paymentMethods = props.paymentMethods.filter(({ type }) => !instantPaymentTypes.includes(type)); + + return { + ...super.formatProps(props), + instantPaymentTypes, + instantPaymentMethods, + paymentMethods + }; + } + get isValid() { return !!this.dropinRef && !!this.dropinRef.state.activePaymentMethod && !!this.dropinRef.state.activePaymentMethod.isValid; } @@ -70,12 +94,15 @@ class DropinElement extends UIElement { * Creates the Drop-in elements */ private handleCreate = () => { - const { paymentMethods, storedPaymentMethods, showStoredPaymentMethods, showPaymentMethods } = this.props; - const commonProps = getCommonProps({ ...this.props, /*onSubmit: this.submit,*/ elementRef: this.elementRef }); + const { paymentMethods, storedPaymentMethods, showStoredPaymentMethods, showPaymentMethods, instantPaymentMethods } = this.props; + + const commonProps = getCommonProps({ ...this.props, elementRef: this.elementRef }); + const storedElements = showStoredPaymentMethods ? createStoredElements(storedPaymentMethods, commonProps, this._parentInstance.create) : []; const elements = showPaymentMethods ? createElements(paymentMethods, commonProps, this._parentInstance.create) : []; + const instantPaymentElements = createInstantPaymentElements(instantPaymentMethods, commonProps, this._parentInstance.create); - return [storedElements, elements]; + return [storedElements, elements, instantPaymentElements]; }; handleAction(action: PaymentAction, props = {}) { diff --git a/packages/lib/src/components/Dropin/components/DropinComponent.scss b/packages/lib/src/components/Dropin/components/DropinComponent.scss index 42322fd0cb..d21d9b8aa0 100644 --- a/packages/lib/src/components/Dropin/components/DropinComponent.scss +++ b/packages/lib/src/components/Dropin/components/DropinComponent.scss @@ -12,6 +12,16 @@ pointer-events: none; } +.adyen-checkout__instant-payment-methods-list { + list-style: none; + margin: 0; + padding: 0; + + li:not(:last-child) { + margin-bottom: 8px; + } +} + /* Forms */ .adyen-checkout__link { diff --git a/packages/lib/src/components/Dropin/components/DropinComponent.tsx b/packages/lib/src/components/Dropin/components/DropinComponent.tsx index 4f5ee01445..7eb1f11617 100644 --- a/packages/lib/src/components/Dropin/components/DropinComponent.tsx +++ b/packages/lib/src/components/Dropin/components/DropinComponent.tsx @@ -8,6 +8,7 @@ import './DropinComponent.scss'; export class DropinComponent extends Component { public state: DropinComponentState = { elements: [], + instantPaymentElements: [], orderStatus: null, isDisabling: false, status: { type: 'loading' }, @@ -21,22 +22,24 @@ export class DropinComponent extends Component { const { order, clientKey, loadingContext } = this.props; - const [storedElementsPromises, elementsPromises] = this.props.onCreateElements(); + const [storedElementsPromises, elementsPromises, instantPaymentsPromises] = this.props.onCreateElements(); const orderStatusPromise = order ? getOrderStatus({ clientKey, loadingContext }, order) : null; - Promise.all([storedElementsPromises, elementsPromises, orderStatusPromise]).then(([storedElements, elements, orderStatus]) => { - this.setState({ elements: [...storedElements, ...elements], orderStatus }); - this.setStatus({ type: 'ready' }); - - if (this.props.modules.analytics) { - this.props.modules.analytics.send({ - containerWidth: this.base && (this.base as HTMLElement).offsetWidth, - paymentMethods: elements.map(e => e.props.type), - component: 'dropin', - flavor: 'dropin' - }); + Promise.all([storedElementsPromises, elementsPromises, instantPaymentsPromises, orderStatusPromise]).then( + ([storedElements, elements, instantPaymentElements, orderStatus]) => { + this.setState({ instantPaymentElements, elements: [...storedElements, ...elements], orderStatus }); + this.setStatus({ type: 'ready' }); + + if (this.props.modules.analytics) { + this.props.modules.analytics.send({ + containerWidth: this.base && (this.base as HTMLElement).offsetWidth, + paymentMethods: elements.map(e => e.props.type), + component: 'dropin', + flavor: 'dropin' + }); + } } - }); + ); }; private setStatus = status => { @@ -88,7 +91,7 @@ export class DropinComponent extends Component +

+ + + ); +} + +export default InstantPaymentMethods; diff --git a/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.test.tsx b/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.test.tsx index eb4100fbf9..ca579247ac 100644 --- a/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.test.tsx +++ b/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.test.tsx @@ -2,6 +2,7 @@ import { shallow, mount } from 'enzyme'; import { h } from 'preact'; import PaymentMethodList from './PaymentMethodList'; import PaymentMethodItem from './PaymentMethodItem'; +import InstantPaymentMethods from './InstantPaymentMethods'; const i18n = { get: key => key }; const index = 0; @@ -24,11 +25,21 @@ const paymentMethods = [ } ]; +const instantPaymentMethods = [ + { + props: { + id: '3', + type: 'googlepay' + } + } +]; + describe('PaymentMethodList', () => { const getWrapper = props => shallow(); test('Renders a PaymentMethodList', () => { const wrapper = getWrapper({ paymentMethods }); + expect(wrapper.hasClass('adyen-checkout__payment-methods-list')).toBe(true); expect(wrapper.find(PaymentMethodItem).length).toBe(2); }); @@ -55,4 +66,9 @@ describe('PaymentMethodList', () => { getWrapper({ paymentMethods, onSelect, openFirstStoredPaymentMethod: true }); expect(onSelect.mock.calls.length).toBe(0); }); + + test('Renders InstantPaymentMethods when prop is provided', () => { + const wrapper = getWrapper({ paymentMethods, instantPaymentMethods }); + expect(wrapper.find(InstantPaymentMethods)).toHaveLength(1); + }); }); diff --git a/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.tsx b/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.tsx index 8790b76b85..5186c32bc6 100644 --- a/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.tsx +++ b/packages/lib/src/components/Dropin/components/PaymentMethod/PaymentMethodList.tsx @@ -6,9 +6,11 @@ import styles from '../DropinComponent.module.scss'; import UIElement from '../../../UIElement'; import { Order, OrderStatus } from '../../../../types'; import OrderPaymentMethods from './OrderPaymentMethods'; +import InstantPaymentMethods from './InstantPaymentMethods'; interface PaymentMethodListProps { paymentMethods: UIElement[]; + instantPaymentMethods: UIElement[]; activePaymentMethod: UIElement; cachedPaymentMethods: object; order?: Order; @@ -27,6 +29,7 @@ interface PaymentMethodListProps { class PaymentMethodList extends Component { public static defaultProps: PaymentMethodListProps = { + instantPaymentMethods: [], paymentMethods: [], activePaymentMethod: null, cachedPaymentMethods: {}, @@ -52,7 +55,7 @@ class PaymentMethodList extends Component { public onSelect = paymentMethod => () => this.props.onSelect(paymentMethod); - render({ paymentMethods, activePaymentMethod, cachedPaymentMethods, isLoading }) { + render({ paymentMethods, instantPaymentMethods, activePaymentMethod, cachedPaymentMethods, isLoading }) { const paymentMethodListClassnames = classNames({ [styles['adyen-checkout__payment-methods-list']]: true, 'adyen-checkout__payment-methods-list': true, @@ -65,6 +68,8 @@ class PaymentMethodList extends Component { )} + {!!instantPaymentMethods.length && } +
    {paymentMethods.map((paymentMethod, index, paymentMethodsCollection) => { const isSelected = activePaymentMethod && activePaymentMethod._id === paymentMethod._id; diff --git a/packages/lib/src/components/Dropin/defaultProps.ts b/packages/lib/src/components/Dropin/defaultProps.ts index 5d9515638c..090f891c00 100644 --- a/packages/lib/src/components/Dropin/defaultProps.ts +++ b/packages/lib/src/components/Dropin/defaultProps.ts @@ -7,9 +7,7 @@ export default { onSelect: () => {}, // triggered when a paymentMethod is selected onDisableStoredPaymentMethod: null, // triggered when a shopper removes a storedPaymentMethod onChange: () => {}, - // onSubmit: () => {}, - // onAdditionalDetails: () => {}, - + instantPaymentMethods: [], amount: {}, installmentOptions: {}, paymentMethodsConfiguration: {}, // per paymentMethod configuration diff --git a/packages/lib/src/components/Dropin/elements/createElements.ts b/packages/lib/src/components/Dropin/elements/createElements.ts index 37c021db67..5199fb8554 100644 --- a/packages/lib/src/components/Dropin/elements/createElements.ts +++ b/packages/lib/src/components/Dropin/elements/createElements.ts @@ -5,7 +5,7 @@ import { PaymentMethod } from '../../../types'; * Returns a filtered (available) list of component Elements * @param components - Array of PaymentMethod objects from the /paymentMethods response * @param props - High level props to be passed through to every component (as defined in utils/getCommonProps) - * @param create - Reference to the main instance `create` method + * @param create - Reference to the main instance `Core#create` method */ const createElements = (components: PaymentMethod[] = [], props, create) => { const elements = components diff --git a/packages/lib/src/components/Dropin/elements/createInstantPaymentElements.ts b/packages/lib/src/components/Dropin/elements/createInstantPaymentElements.ts new file mode 100644 index 0000000000..058e2f6717 --- /dev/null +++ b/packages/lib/src/components/Dropin/elements/createInstantPaymentElements.ts @@ -0,0 +1,14 @@ +import createElements from './createElements'; +import { PaymentMethod } from '../../../types'; +import UIElement from '../../UIElement'; + +/** + * Returns a filtered (available) list of InstantPaymentMethods Elements + * @param paymentMethods - Instant payment methods + * @param props - Props to be passed through to every paymentMethod + * @param create - Reference to the main instance `Core#create` method + */ +const createInstantPaymentElements = (paymentMethods: PaymentMethod[] = [], props, create): Promise | [] => + paymentMethods.length ? createElements(paymentMethods, { ...props, isInstantPayment: true }, create) : []; + +export default createInstantPaymentElements; diff --git a/packages/lib/src/components/Dropin/types.ts b/packages/lib/src/components/Dropin/types.ts index cb045690c2..befd60323c 100644 --- a/packages/lib/src/components/Dropin/types.ts +++ b/packages/lib/src/components/Dropin/types.ts @@ -3,6 +3,8 @@ import UIElement from '../UIElement'; import { UIElementProps } from '../types'; import { PaymentMethodsConfiguration } from '../../core/types'; +export type InstantPaymentTypes = 'paywithgoogle' | 'applepay'; + export interface DropinElementProps extends UIElementProps { /** * Configure each payment method displayed on the Drop-in @@ -27,6 +29,20 @@ export interface DropinElementProps extends UIElementProps { */ showPaymentMethods?: boolean; + /** + * Show wallet payment methods to show on top of the regular payment + * method list. + * + * @defaultValue [] + */ + instantPaymentTypes: InstantPaymentTypes[]; + + /** + * Instant Payment methods derived from the instantPaymentTypes property + * @internal + */ + instantPaymentMethods?: PaymentMethod[]; + openFirstStoredPaymentMethod?: boolean; openFirstPaymentMethod?: boolean; onSubmit?: (data, component) => void; @@ -61,6 +77,7 @@ interface DropinStatus { export interface DropinComponentState { elements: any[]; + instantPaymentElements: UIElement[]; status: DropinStatus; activePaymentMethod: UIElement; cachedPaymentMethods: object; diff --git a/packages/lib/src/components/GooglePay/components/GooglePayButton.scss b/packages/lib/src/components/GooglePay/components/GooglePayButton.scss index d1745daf63..54575b90e7 100644 --- a/packages/lib/src/components/GooglePay/components/GooglePayButton.scss +++ b/packages/lib/src/components/GooglePay/components/GooglePayButton.scss @@ -1,3 +1,7 @@ +.adyen-checkout__paywithgoogle { + height: 48px; +} + .adyen-checkout__paywithgoogle > div > button { &, &.long, diff --git a/packages/lib/src/components/UIElement.test.ts b/packages/lib/src/components/UIElement.test.ts index c103d51657..372c707a11 100644 --- a/packages/lib/src/components/UIElement.test.ts +++ b/packages/lib/src/components/UIElement.test.ts @@ -144,4 +144,18 @@ describe('UIElement', () => { expect(pa.props.challengeWindowSize).toEqual('02'); }); }); + + describe('submit', () => { + test('should close active payment method if submit is called by instant payment method', () => { + const onSubmit = jest.fn(); + const elementRef = { closeActivePaymentMethod: jest.fn() }; + const uiElement = new UIElement({ isInstantPayment: true, onSubmit, elementRef }); + + jest.spyOn(uiElement, 'isValid', 'get').mockReturnValue(true); + + uiElement.submit(); + + expect(elementRef.closeActivePaymentMethod).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/packages/lib/src/components/UIElement.tsx b/packages/lib/src/components/UIElement.tsx index 8fcba1d162..fbff8e5962 100644 --- a/packages/lib/src/components/UIElement.tsx +++ b/packages/lib/src/components/UIElement.tsx @@ -39,6 +39,10 @@ export class UIElement

    extends BaseElement

    { } onSubmit(): void { + if (this.props.isInstantPayment) { + this.elementRef.closeActivePaymentMethod(); + } + if (this.props.onSubmit) { // Classic flow this.props.onSubmit({ data: this.data, isValid: this.isValid }, this.elementRef); diff --git a/packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.scss b/packages/lib/src/components/internal/ContentSeparator/ContentSeparator.scss similarity index 95% rename from packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.scss rename to packages/lib/src/components/internal/ContentSeparator/ContentSeparator.scss index 436b62be93..96296ebfcb 100644 --- a/packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.scss +++ b/packages/lib/src/components/internal/ContentSeparator/ContentSeparator.scss @@ -7,6 +7,7 @@ justify-content:center; align-items: center; color: $color-gray-darker; + white-space: nowrap; &:after, &:before { diff --git a/packages/lib/src/components/internal/ContentSeparator/ContentSeparator.tsx b/packages/lib/src/components/internal/ContentSeparator/ContentSeparator.tsx new file mode 100644 index 0000000000..6383ebfbe1 --- /dev/null +++ b/packages/lib/src/components/internal/ContentSeparator/ContentSeparator.tsx @@ -0,0 +1,14 @@ +import { h } from 'preact'; +import useCoreContext from '../../../core/Context/useCoreContext'; +import './ContentSeparator.scss'; + +interface ContentSeparatorProps { + label?: string; +} + +function ContentSeparator({ label = 'qrCodeOrApp' }: ContentSeparatorProps) { + const { i18n } = useCoreContext(); + return

    {i18n.get(label)}
    ; +} + +export default ContentSeparator; diff --git a/packages/lib/src/components/internal/IssuerList/ContentSeparator/index.ts b/packages/lib/src/components/internal/ContentSeparator/index.ts similarity index 100% rename from packages/lib/src/components/internal/IssuerList/ContentSeparator/index.ts rename to packages/lib/src/components/internal/ContentSeparator/index.ts diff --git a/packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.tsx b/packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.tsx deleted file mode 100644 index bb3b3142de..0000000000 --- a/packages/lib/src/components/internal/IssuerList/ContentSeparator/ContentSeparator.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { h } from 'preact'; -import useCoreContext from '../../../../core/Context/useCoreContext'; -import './ContentSeparator.scss'; - -function ContentSeparator() { - const { i18n } = useCoreContext(); - return
    {i18n.get('qrCodeOrApp')}
    ; -} - -export default ContentSeparator; diff --git a/packages/lib/src/components/internal/IssuerList/IssuerList.tsx b/packages/lib/src/components/internal/IssuerList/IssuerList.tsx index a1b8845f37..da85feda39 100644 --- a/packages/lib/src/components/internal/IssuerList/IssuerList.tsx +++ b/packages/lib/src/components/internal/IssuerList/IssuerList.tsx @@ -4,7 +4,7 @@ import useForm from '../../../utils/useForm'; import { renderFormField } from '../FormFields'; import Field from '../FormFields/Field'; import IssuerButtonGroup from './IssuerButtonGroup'; -import ContentSeparator from './ContentSeparator'; +import ContentSeparator from '../ContentSeparator'; import useCoreContext from '../../../core/Context/useCoreContext'; import { ValidatorRules } from '../../../utils/Validator/Validator'; import { IssuerListProps } from './types'; diff --git a/packages/lib/src/components/types.ts b/packages/lib/src/components/types.ts index 722b5af55e..65a4f91434 100644 --- a/packages/lib/src/components/types.ts +++ b/packages/lib/src/components/types.ts @@ -41,6 +41,8 @@ export interface UIElementProps extends BaseElementProps { onPaymentCompleted?: (result: any, element: UIElement) => void; beforeRedirect?: (resolve, reject, redirectData, element: UIElement) => void; + isInstantPayment?: boolean; + type?: string; name?: string; icon?: string; diff --git a/packages/lib/src/language/locales/ar.json b/packages/lib/src/language/locales/ar.json index 1ff9c36582..c2444d2952 100644 --- a/packages/lib/src/language/locales/ar.json +++ b/packages/lib/src/language/locales/ar.json @@ -206,5 +206,6 @@ "ach.encryptedBankLocationId.aria.iframeTitle": "الإطار المضمن لرقم التوجيه البنكي المؤمن", "ach.encryptedBankLocationId.aria.label": "حقل رقم التوجيه البنكي", "pix.instructions": "افتح التطبيق باستخدام مفتاح PIX المسجل، واختر الدفع باستخدام PIX وامسح رمز الاستجابة السريعة ضوئيًا أو انسخ الرمز والصقه", - "twint.saved": "المحفوظة" + "twint.saved": "المحفوظة", + "orPayWith": "أو الدفع باستخدام" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/cs-CZ.json b/packages/lib/src/language/locales/cs-CZ.json index 85147e3e33..0b267e8bdd 100644 --- a/packages/lib/src/language/locales/cs-CZ.json +++ b/packages/lib/src/language/locales/cs-CZ.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Pole pro bankovní účet", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe pro číslo zabezpečeného kódu banky", "ach.encryptedBankLocationId.aria.label": "Pole pro kód banky", - "twint.saved": "uloženo" + "twint.saved": "uloženo", + "orPayWith": "nebo zaplaťte pomocí" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/da-DK.json b/packages/lib/src/language/locales/da-DK.json index 572dc7a2a6..5a1663f0da 100644 --- a/packages/lib/src/language/locales/da-DK.json +++ b/packages/lib/src/language/locales/da-DK.json @@ -206,5 +206,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Felt til bankkonto", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe til registreringsnummer for sikret bank", "ach.encryptedBankLocationId.aria.label": "Felt til registreringsnummer for bank", - "twint.saved": "gemt" + "twint.saved": "gemt", + "orPayWith": "eller betal med" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/de-DE.json b/packages/lib/src/language/locales/de-DE.json index b9c3b3cc43..caf560f7ed 100644 --- a/packages/lib/src/language/locales/de-DE.json +++ b/packages/lib/src/language/locales/de-DE.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Feld „Bankkonto“", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe für gesicherte BLZ", "ach.encryptedBankLocationId.aria.label": "Bankleitzahl-Feld", - "twint.saved": "hinterlegt" + "twint.saved": "hinterlegt", + "orPayWith": "oder bezahlen Sie mit" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/el-GR.json b/packages/lib/src/language/locales/el-GR.json index 6fccba3641..843db47556 100644 --- a/packages/lib/src/language/locales/el-GR.json +++ b/packages/lib/src/language/locales/el-GR.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Πεδίο τραπεζικού λογαριασμού", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe για ασφαλή αριθμό κωδικού υποκαταστήματος τράπεζας", "ach.encryptedBankLocationId.aria.label": "Πεδίο αριθμού κωδικού υποκαταστήματος τράπεζας", - "twint.saved": "αποθηκεύτηκε" + "twint.saved": "αποθηκεύτηκε", + "orPayWith": "ή πληρώστε με" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/en-US.json b/packages/lib/src/language/locales/en-US.json index e0aa720287..83f9e2396e 100644 --- a/packages/lib/src/language/locales/en-US.json +++ b/packages/lib/src/language/locales/en-US.json @@ -207,5 +207,6 @@ "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe for secured bank routing number", "ach.encryptedBankLocationId.aria.label": "Bank routing number field", "pix.instructions": "Open the app with the PIX registered key, choose Pay with PIX and scan the QR Code or copy and paste the code", - "twint.saved": "saved" + "twint.saved": "saved", + "orPayWith": "or pay with" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/es-ES.json b/packages/lib/src/language/locales/es-ES.json index 4c423a05b0..32d1355ffb 100644 --- a/packages/lib/src/language/locales/es-ES.json +++ b/packages/lib/src/language/locales/es-ES.json @@ -200,5 +200,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Campo de la cuenta bancaria", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe del número de ruta del banco asegurado", "ach.encryptedBankLocationId.aria.label": "Campo del número de ruta del banco", - "twint.saved": "guardado" + "twint.saved": "guardado", + "orPayWith": "o pague con" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/fi-FI.json b/packages/lib/src/language/locales/fi-FI.json index 34cdb32810..3ac5e81232 100644 --- a/packages/lib/src/language/locales/fi-FI.json +++ b/packages/lib/src/language/locales/fi-FI.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Pankkitilikenttä", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe suojatulle pankin reititysnumerolle", "ach.encryptedBankLocationId.aria.label": "Pankin reititysnumerokenttä", - "twint.saved": "tallennettu" + "twint.saved": "tallennettu", + "orPayWith": "tai maksa" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/fr-FR.json b/packages/lib/src/language/locales/fr-FR.json index 2aa62f3e33..b8b6c17cb4 100644 --- a/packages/lib/src/language/locales/fr-FR.json +++ b/packages/lib/src/language/locales/fr-FR.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Champ du compte bancaire", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe pour le numéro de routage du compte avec garantie", "ach.encryptedBankLocationId.aria.label": "Champ du numéro de routage", - "twint.saved": "stocké" + "twint.saved": "stocké", + "orPayWith": "ou payez avec" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/hr-HR.json b/packages/lib/src/language/locales/hr-HR.json index 69b86da29a..29364f21e6 100644 --- a/packages/lib/src/language/locales/hr-HR.json +++ b/packages/lib/src/language/locales/hr-HR.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Polje za broj bankovnog računa", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe za identifikacijski broj prepaid banke", "ach.encryptedBankLocationId.aria.label": "Polje za identifikacijski broj banke", - "twint.saved": "spremljeno" + "twint.saved": "spremljeno", + "orPayWith": "ili platite s" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/hu-HU.json b/packages/lib/src/language/locales/hu-HU.json index 8fcce932c4..c6ac016f26 100644 --- a/packages/lib/src/language/locales/hu-HU.json +++ b/packages/lib/src/language/locales/hu-HU.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Bankszámla mezője", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe a biztonságos bankazonosító kódhoz", "ach.encryptedBankLocationId.aria.label": "Bankazonosító kód mezője", - "twint.saved": "mentve" + "twint.saved": "mentve", + "orPayWith": "vagy fizessen ezzel:" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/it-IT.json b/packages/lib/src/language/locales/it-IT.json index 6521b2f2ce..5f91c3f46d 100644 --- a/packages/lib/src/language/locales/it-IT.json +++ b/packages/lib/src/language/locales/it-IT.json @@ -203,5 +203,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Campo conto bancario", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe per numero di routing bancario sicuro", "ach.encryptedBankLocationId.aria.label": "Campo numero di routing bancario", - "twint.saved": "memorizzato" + "twint.saved": "memorizzato", + "orPayWith": "oppure paga con" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/ja-JP.json b/packages/lib/src/language/locales/ja-JP.json index 8a41dbe200..4ecd4b4660 100644 --- a/packages/lib/src/language/locales/ja-JP.json +++ b/packages/lib/src/language/locales/ja-JP.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "銀行口座フィールド", "ach.encryptedBankLocationId.aria.iframeTitle": "保護された銀行支店番号の iframe", "ach.encryptedBankLocationId.aria.label": "銀行支店番号フィールド", - "twint.saved": "を保存しました" + "twint.saved": "を保存しました", + "orPayWith": "または次の方法で支払う" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/ko-KR.json b/packages/lib/src/language/locales/ko-KR.json index d978de9d65..d564a127f4 100644 --- a/packages/lib/src/language/locales/ko-KR.json +++ b/packages/lib/src/language/locales/ko-KR.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "은행 계좌 입력란", "ach.encryptedBankLocationId.aria.iframeTitle": "은행 라우팅 번호 보안을 위한 Iframe", "ach.encryptedBankLocationId.aria.label": "은행 라우팅 번호 입력란", - "twint.saved": "저장됨" + "twint.saved": "저장됨", + "orPayWith": "기타 결제 수단:" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/nl-NL.json b/packages/lib/src/language/locales/nl-NL.json index 39ba0a318f..4927d3a5aa 100644 --- a/packages/lib/src/language/locales/nl-NL.json +++ b/packages/lib/src/language/locales/nl-NL.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Veld voor bankrekening", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe voor beveiligde BIC-code", "ach.encryptedBankLocationId.aria.label": "Veld voor BIC-code", - "twint.saved": "opgeslagen" + "twint.saved": "opgeslagen", + "orPayWith": "of betaal met" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/no-NO.json b/packages/lib/src/language/locales/no-NO.json index 777390bcbb..2264960b54 100644 --- a/packages/lib/src/language/locales/no-NO.json +++ b/packages/lib/src/language/locales/no-NO.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Bankkontofelt", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe for sikret bankdirigeringsnummer", "ach.encryptedBankLocationId.aria.label": "Felt for bankdirigeringsnummer", - "twint.saved": "lagret" + "twint.saved": "lagret", + "orPayWith": "eller betal med" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/pl-PL.json b/packages/lib/src/language/locales/pl-PL.json index 19f1f73ee2..625a64c56b 100644 --- a/packages/lib/src/language/locales/pl-PL.json +++ b/packages/lib/src/language/locales/pl-PL.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Pole rachunku bankowego", "ach.encryptedBankLocationId.aria.iframeTitle": "Element Iframe dla zabezpieczonego kodu bankowego (Bank Routing Number)", "ach.encryptedBankLocationId.aria.label": "Pole kodu bankowego (Bank Routing Number)", - "twint.saved": "zapisano" + "twint.saved": "zapisano", + "orPayWith": "lub zapłać" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/pt-BR.json b/packages/lib/src/language/locales/pt-BR.json index a78fbee211..5c4130d4f4 100644 --- a/packages/lib/src/language/locales/pt-BR.json +++ b/packages/lib/src/language/locales/pt-BR.json @@ -203,5 +203,6 @@ "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe para número de roteamento bancário seguro", "ach.encryptedBankLocationId.aria.label": "Campo de número de roteamento bancário", "pix.instructions": "Abra o app com sua chave PIX cadastrada, escolha Pagar com Pix e escaneie o QR Code ou copie e cole o código", - "twint.saved": "salvo" + "twint.saved": "salvo", + "orPayWith": "ou pague com" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/ro-RO.json b/packages/lib/src/language/locales/ro-RO.json index c318145746..67fe940df7 100644 --- a/packages/lib/src/language/locales/ro-RO.json +++ b/packages/lib/src/language/locales/ro-RO.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Câmp aferent contului bancar", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe pentru numărul securizat de direcționare bancară (routing number)", "ach.encryptedBankLocationId.aria.label": "Câmp aferent codului de direcționare bancară (routing number)", - "twint.saved": "salvat" + "twint.saved": "salvat", + "orPayWith": "sau plătiți cu" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/ru-RU.json b/packages/lib/src/language/locales/ru-RU.json index 93bf4b4cce..5187f54c6c 100644 --- a/packages/lib/src/language/locales/ru-RU.json +++ b/packages/lib/src/language/locales/ru-RU.json @@ -202,5 +202,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Поле банковского счета", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe для защиты маршрутного номера банка", "ach.encryptedBankLocationId.aria.label": "Поле маршрутного номера банка", - "twint.saved": "сохранено" + "twint.saved": "сохранено", + "orPayWith": "или заплатите через" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/sk-SK.json b/packages/lib/src/language/locales/sk-SK.json index d04d2004f0..bfa2bfe1b5 100644 --- a/packages/lib/src/language/locales/sk-SK.json +++ b/packages/lib/src/language/locales/sk-SK.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Pole bankového účtu", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe pre zabezpečené smerovacie číslo banky", "ach.encryptedBankLocationId.aria.label": "Pole smerovacieho čísla banky", - "twint.saved": "uložené" + "twint.saved": "uložené", + "orPayWith": "alebo zaplatiť pomocou" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/sl-SI.json b/packages/lib/src/language/locales/sl-SI.json index 9558bf906e..842bd7fd52 100644 --- a/packages/lib/src/language/locales/sl-SI.json +++ b/packages/lib/src/language/locales/sl-SI.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Polje z bančnim računom", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe za zavarovano kodo banke", "ach.encryptedBankLocationId.aria.label": "Polje s kodo banke", - "twint.saved": "shranjeno" + "twint.saved": "shranjeno", + "orPayWith": "ali plačajte s/z" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/sv-SE.json b/packages/lib/src/language/locales/sv-SE.json index 4ebc4a588e..ff1bdb8b19 100644 --- a/packages/lib/src/language/locales/sv-SE.json +++ b/packages/lib/src/language/locales/sv-SE.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "Fält för bankkontonummer", "ach.encryptedBankLocationId.aria.iframeTitle": "Iframe för säkrat clearingnummer", "ach.encryptedBankLocationId.aria.label": "Fält för clearingnummer", - "twint.saved": "sparat" + "twint.saved": "sparat", + "orPayWith": "eller betala med" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/zh-CN.json b/packages/lib/src/language/locales/zh-CN.json index 5c0bfa83cc..973a1afe58 100644 --- a/packages/lib/src/language/locales/zh-CN.json +++ b/packages/lib/src/language/locales/zh-CN.json @@ -204,5 +204,6 @@ "ach.encryptedBankAccountNumber.aria.label": "银行账号字段", "ach.encryptedBankLocationId.aria.iframeTitle": "安全银行路由电汇编码 Iframe", "ach.encryptedBankLocationId.aria.label": "银行路由电汇编码字段", - "twint.saved": "已保存" + "twint.saved": "已保存", + "orPayWith": "或使用以下方式支付" } \ No newline at end of file diff --git a/packages/lib/src/language/locales/zh-TW.json b/packages/lib/src/language/locales/zh-TW.json index d428dcc22d..c83e6c752a 100644 --- a/packages/lib/src/language/locales/zh-TW.json +++ b/packages/lib/src/language/locales/zh-TW.json @@ -205,5 +205,6 @@ "ach.encryptedBankAccountNumber.aria.label": "銀行帳戶欄位", "ach.encryptedBankLocationId.aria.iframeTitle": "安全銀行匯款路徑編號的 IFrame", "ach.encryptedBankLocationId.aria.label": "銀行匯款路徑編號欄位", - "twint.saved": "儲存的" + "twint.saved": "儲存的", + "orPayWith": "或透過以下方式支付:" } \ No newline at end of file diff --git a/packages/lib/src/types/index.ts b/packages/lib/src/types/index.ts index af2fbd531c..af93a08e67 100644 --- a/packages/lib/src/types/index.ts +++ b/packages/lib/src/types/index.ts @@ -97,6 +97,11 @@ export interface PaymentMethod { * Configuration props as set by the merchant in the CA and received in the PM object in the /paymentMethods response */ configuration?: object; + + /** + * Brands available for this payment method + */ + brands?: string[]; } export interface StoredPaymentMethod extends PaymentMethod { diff --git a/packages/playground/src/pages/Dropin/manual.js b/packages/playground/src/pages/Dropin/manual.js index 4712110f05..c7aef5bd72 100644 --- a/packages/playground/src/pages/Dropin/manual.js +++ b/packages/playground/src/pages/Dropin/manual.js @@ -67,6 +67,11 @@ export async function initManual() { enableStoreDetails: false, hasHolderName: true, holderNameRequired: true + }, + paymentMethodsConfiguration: { + paywithgoogle: { + buttonType: 'plain' + } } } }); @@ -128,7 +133,11 @@ export async function initManual() { return Promise.resolve(true); } - const dropin = checkout.create('dropin').mount('#dropin-container'); + const dropin = checkout + .create('dropin', { + instantPaymentTypes: ['paywithgoogle'] + }) + .mount('#dropin-container'); handleRedirectResult(); diff --git a/packages/playground/src/pages/Dropin/session.js b/packages/playground/src/pages/Dropin/session.js index f337eb6c88..425453200a 100644 --- a/packages/playground/src/pages/Dropin/session.js +++ b/packages/playground/src/pages/Dropin/session.js @@ -27,9 +27,18 @@ export async function initSession() { }, onError: (error, component) => { console.error(error.message, component); + }, + paymentMethodsConfiguration: { + paywithgoogle: { + buttonType: 'plain' + } } }); - const dropin = checkout.create('dropin').mount('#dropin-container'); + const dropin = checkout + .create('dropin', { + instantPaymentTypes: ['paywithgoogle'] + }) + .mount('#dropin-container'); return [checkout, dropin]; }