diff --git a/packages/lib/src/components/Dropin/defaultProps.ts b/packages/lib/src/components/Dropin/defaultProps.ts index 090f891c..27ab4b48 100644 --- a/packages/lib/src/components/Dropin/defaultProps.ts +++ b/packages/lib/src/components/Dropin/defaultProps.ts @@ -2,7 +2,6 @@ export default { isDropin: true, onReady: () => {}, // triggered when the Dropin is fully loaded onComplete: () => {}, // triggered when the shopper completes a payment - onCancel: () => {}, // triggered when payment is cancelled (for example, a payment overlay is closed) onError: () => {}, // triggered when an error occurs (for example, could not submit a payment) onSelect: () => {}, // triggered when a paymentMethod is selected onDisableStoredPaymentMethod: null, // triggered when a shopper removes a storedPaymentMethod diff --git a/packages/lib/src/components/Giftcard/Giftcard.tsx b/packages/lib/src/components/Giftcard/Giftcard.tsx index 7d8afcad..cb179b56 100644 --- a/packages/lib/src/components/Giftcard/Giftcard.tsx +++ b/packages/lib/src/components/Giftcard/Giftcard.tsx @@ -7,6 +7,7 @@ import PayButton from '../internal/PayButton'; import AdyenCheckoutError from '../../core/Errors/AdyenCheckoutError'; import { PaymentAmount } from '../../types'; import { PaymentResponse } from '../types'; +import { GiftCardElementData } from './types'; export class GiftcardElement extends UIElement { public static type = 'giftcard'; @@ -22,10 +23,7 @@ export class GiftcardElement extends UIElement { }; } - /** - * Formats the component data output - */ - formatData() { + formatData(): GiftCardElementData { return { paymentMethod: { type: this.constructor['type'], diff --git a/packages/lib/src/components/Giftcard/types.ts b/packages/lib/src/components/Giftcard/types.ts new file mode 100644 index 00000000..efa783e9 --- /dev/null +++ b/packages/lib/src/components/Giftcard/types.ts @@ -0,0 +1,8 @@ +export interface GiftCardElementData { + paymentMethod: { + type: 'giftcard'; + brand: string; + encryptedCardNumber: string; + encryptedSecurityCode: string; + }; +} diff --git a/packages/lib/src/components/types.ts b/packages/lib/src/components/types.ts index b4a38c8a..9d0cd164 100644 --- a/packages/lib/src/components/types.ts +++ b/packages/lib/src/components/types.ts @@ -43,12 +43,20 @@ export interface PaymentData extends PaymentMethodData { storePaymentMethod?: boolean; } +export type ResultCode = 'Authorised' | 'Cancelled' | 'ChallengeShopper' | 'Error' | 'IdentifyShopper' | 'Pending'; + +export interface OnPaymentCompletedData { + sessionData: string; + sessionResult: string; + resultCode: ResultCode; +} + export interface PaymentResponse { action?: PaymentAction; resultCode: string; sessionData?: string; - order?: Order; sessionResult?: string; + order?: Order; } export interface RawPaymentResponse extends PaymentResponse { diff --git a/packages/lib/src/core/ProcessResponse/PaymentMethodsResponse/PaymentMethodsResponse.ts b/packages/lib/src/core/ProcessResponse/PaymentMethodsResponse/PaymentMethodsResponse.ts index 34b7e62d..6bad3c26 100644 --- a/packages/lib/src/core/ProcessResponse/PaymentMethodsResponse/PaymentMethodsResponse.ts +++ b/packages/lib/src/core/ProcessResponse/PaymentMethodsResponse/PaymentMethodsResponse.ts @@ -1,11 +1,12 @@ import { PaymentMethod, StoredPaymentMethod } from '../../../types'; import { checkPaymentMethodsResponse, processPaymentMethods, processStoredPaymentMethods } from './utils'; +import { PaymentMethodsResponse as PaymentMethodsResponseType } from './types'; class PaymentMethodsResponse { public paymentMethods: PaymentMethod[] = []; public storedPaymentMethods: StoredPaymentMethod[] = []; - constructor(response: PaymentMethodsResponse, options = {}) { + constructor(response: PaymentMethodsResponseType, options = {}) { checkPaymentMethodsResponse(response); this.paymentMethods = response ? processPaymentMethods(response.paymentMethods, options) : []; diff --git a/packages/lib/src/core/core.ts b/packages/lib/src/core/core.ts index d291fd47..3707eca8 100644 --- a/packages/lib/src/core/core.ts +++ b/packages/lib/src/core/core.ts @@ -29,11 +29,10 @@ class Core { buildId: process.env.ADYEN_BUILD_ID }; - constructor(options: CoreOptions) { + constructor(props: CoreOptions) { this.create = this.create.bind(this); this.createFromAction = this.createFromAction.bind(this); - - this.setOptions(options); + this.setOptions(props); // Expose version number for npm builds window['adyenWebVersion'] = Core.version.version; @@ -46,8 +45,15 @@ class Core { return this.session .setupSession(this.options) .then(sessionResponse => { - const amount = this.options.order ? this.options.order.remainingAmount : sessionResponse.amount; - this.setOptions({ ...sessionResponse, amount }); + const { amount, shopperLocale, paymentMethods, ...rest } = sessionResponse; + + this.setOptions({ + ...rest, + amount: this.options.order ? this.options.order.remainingAmount : amount, + paymentMethodsResponse: this.options.paymentMethodsResponse || paymentMethods, + locale: this.options.locale || shopperLocale + }); + return this; }) .catch(error => { @@ -59,44 +65,23 @@ class Core { return Promise.resolve(this); } - /** - * Submit data to payments using the onSubmit event or the session flow if available - * @param data - - */ - public submitPayment(data): void { - if (this.options.onSubmit) return this.options.onSubmit(data); - - if (this.session) { - this.session - .submitPayment(data) - .then(response => { - if (response.action) { - if (this.options.onPaymentSubmitted) this.options.onPaymentSubmitted(response, this); - } else { - if (this.options.onPaymentCompleted) this.options.onPaymentCompleted(response, this); - } - }) - .catch(error => { - if (this.options.onError) this.options.onError(error); - }); - } - } - /** * Submits details using onAdditionalDetails or the session flow if available * @param details - */ public submitDetails(details): void { - if (this.options.onAdditionalDetails) return this.options.onAdditionalDetails(details); + if (this.options.onAdditionalDetails) { + return this.options.onAdditionalDetails(details); + } if (this.session) { this.session .submitDetails(details) .then(response => { - if (this.options.onPaymentCompleted) this.options.onPaymentCompleted(response, this); + this.options.onPaymentCompleted?.(response); }) .catch(error => { - if (this.options.onError) this.options.onError(error, this); + this.options.onError?.(error); }); } } @@ -188,7 +173,7 @@ class Core { * @param options - the config object passed when AdyenCheckout is initialised * @returns this */ - private setOptions = (options): this => { + private setOptions = (options: CoreOptions): this => { if (hasOwnProperty(options?.paymentMethodsConfiguration, 'scheme')) { console.warn( 'WARNING: You cannot define a property "scheme" on the paymentMethodsConfiguration object - it should be defined as "card" otherwise it will be ignored' @@ -198,7 +183,6 @@ class Core { this.options = { ...this.options, ...options }; this.options.loadingContext = resolveEnvironment(this.options.environment); this.options.cdnContext = resolveCDNEnvironment(this.options.resourceEnvironment || this.options.environment); - this.options.locale = this.options.locale || this.options.shopperLocale; // In a sessions flow setOptions gets called twice, but we only need one set of modules (except for i18n needs to be re-initialised as the options settle) this.modules = { @@ -209,8 +193,7 @@ class Core { srPanel: this.modules?.srPanel ?? new SRPanel(this.options.srConfig) }; - this.paymentMethodsResponse = new PaymentMethodsResponse(this.options.paymentMethodsResponse ?? this.options.paymentMethods, this.options); - delete this.options.paymentMethods; + this.paymentMethodsResponse = new PaymentMethodsResponse(this.options.paymentMethodsResponse, this.options); // Check for clientKey/environment mismatch const clientKeyType = this.options.clientKey?.substr(0, 4); diff --git a/packages/lib/src/core/types.ts b/packages/lib/src/core/types.ts index 8f829314..e1a324bb 100644 --- a/packages/lib/src/core/types.ts +++ b/packages/lib/src/core/types.ts @@ -3,6 +3,15 @@ import { PaymentMethods, PaymentMethodOptions, PaymentActionsType, PaymentAmount import { AnalyticsOptions } from './Analytics/types'; import { PaymentMethodsResponse } from './ProcessResponse/PaymentMethodsResponse/types'; import { RiskModuleOptions } from './RiskModule/RiskModule'; +import { ActionHandledReturnObject, OnPaymentCompletedData, PaymentData } from '../components/types'; +import UIElement from '../components/UIElement'; +import AdyenCheckoutError from './Errors/AdyenCheckoutError'; +import { GiftCardElementData } from '../components/Giftcard/types'; +import { SRPanelProps } from './Errors/types'; + +type PromiseResolve = typeof Promise.resolve; + +type PromiseReject = typeof Promise.reject; export interface CoreOptions { session?: any; @@ -11,6 +20,11 @@ export interface CoreOptions { */ environment?: 'test' | 'live' | 'live-us' | 'live-au' | 'live-apse' | 'live-in' | string; + /** + * Show or hides a Pay Button for each payment method + */ + showPayButton?: boolean; + /** * A public key linked to your web service user, used for {@link https://docs.adyen.com/user-management/client-side-authentication | client-side authentication}. */ @@ -66,9 +80,9 @@ export interface CoreOptions { removePaymentMethods?: string[]; /** - * @internal - * */ - loadingContext?: string; + * Screen Reader configuration + */ + srConfig?: SRPanelProps; /** * @internal @@ -84,8 +98,45 @@ export interface CoreOptions { order?: Order; - //TODO: discuss if can remove this - [key: string]: any; + setStatusAutomatically?: boolean; + + beforeRedirect?(resolve: PromiseResolve, reject: PromiseReject, redirectData: { url: string; method: string; data?: any }): Promise; + + beforeSubmit?(state: any, element: UIElement, actions: { resolve: PromiseResolve; reject: PromiseReject }): Promise; + + onPaymentCompleted?(data: OnPaymentCompletedData, element?: UIElement): void; + + onSubmit?(state: any, element: UIElement): void; + + onAdditionalDetails?(state: any, element?: UIElement): void; + + onActionHandled?(data: ActionHandledReturnObject): void; + + onChange?(state: any, element: UIElement): void; + + onError?(error: AdyenCheckoutError, element?: UIElement): void; + + onBalanceCheck?(resolve: PromiseResolve, reject: PromiseReject, data: GiftCardElementData): Promise; + + onOrderRequest?(resolve: PromiseResolve, reject: PromiseReject, data: PaymentData): Promise; + + /** + * Only used in Components combined with Sessions flow + * Callback used to inform when the order is created. + * https://docs.adyen.com/payment-methods/gift-cards/web-component?tab=config-sessions_1 + */ + onOrderCreated?(order: Order): void; + + /** + * Used only in the Donation Component when shopper declines to donate + * https://docs.adyen.com/online-payments/donations/web-component + */ + onCancel?(): void; + + /** + * @internal + */ + loadingContext?: string; } export type PaymentMethodsConfiguration = diff --git a/packages/lib/src/types/index.ts b/packages/lib/src/types/index.ts index 08f05ee9..426ab779 100644 --- a/packages/lib/src/types/index.ts +++ b/packages/lib/src/types/index.ts @@ -2,6 +2,7 @@ import paymentMethods from '../components'; import { ADDRESS_SCHEMA } from '../components/internal/Address/constants'; import actionTypes from '../core/ProcessResponse/PaymentAction/actionTypes'; import { InstallmentOptions } from '../components/Card/components/CardInput/components/types'; +import { ResultCode } from '../components/types'; export type PaymentActionsType = keyof typeof actionTypes; @@ -301,6 +302,11 @@ export type CheckoutSessionSetupResponse = { paymentMethods: any; returnUrl: string; configuration: SessionConfiguration; + /** + * 'shopperLocale' set during session creation. + * @defaultValue en-US + */ + shopperLocale: string; }; export type CheckoutSessionPaymentResponse = { @@ -312,8 +318,9 @@ export type CheckoutSessionPaymentResponse = { export type CheckoutSessionDetailsResponse = { sessionData: string; + sessionResult: string; + resultCode: ResultCode; status?: string; - resultCode: string; action?: PaymentAction; }; diff --git a/packages/playground/src/pages/Helpers/Helpers.js b/packages/playground/src/pages/Helpers/Helpers.js index c6c23814..4ce6992e 100644 --- a/packages/playground/src/pages/Helpers/Helpers.js +++ b/packages/playground/src/pages/Helpers/Helpers.js @@ -43,7 +43,10 @@ getPaymentMethods({ amount, shopperLocale }).then(async paymentMethodsResponse = 'https://www.patagonia.com/static/on/demandware.static/-/Library-Sites-PatagoniaShared/default/dwb396273f/content-banners/100-planet-hero-desktop.jpg', description: 'Lorem ipsum...', logoUrl: 'https://i.ebayimg.com/images/g/aTwAAOSwfu9dfX4u/s-l300.jpg', - name: 'Test Charity' + name: 'Test Charity', + onCancel(data) { + console.log(data); + } }) .mount('.donation-field'); diff --git a/packages/playground/src/pages/Wallets/Wallets.js b/packages/playground/src/pages/Wallets/Wallets.js index 87162c54..4638108f 100644 --- a/packages/playground/src/pages/Wallets/Wallets.js +++ b/packages/playground/src/pages/Wallets/Wallets.js @@ -134,11 +134,6 @@ getPaymentMethods({ amount, shopperLocale }).then(async paymentMethodsResponse = onError: (error, component) => { component.setStatus('ready'); console.log('paypal onError', error); - }, - - onCancel: (data, component) => { - component.setStatus('ready'); - console.log('paypal onCancel', data); } }) .mount('.paypal-field');