From 74aa351e767ba1712bb48518fa234a99adf78c78 Mon Sep 17 00:00:00 2001 From: bc-nick Date: Mon, 16 Dec 2024 17:07:47 +0100 Subject: [PATCH 1/6] feat(payment): PAYPAL-4937 updated PaymentMethodRequestSender by adding an additional method --- .../src/common/http-request/responses.mock.ts | 24 +++++- .../payment/headless-payment-method-config.ts | 8 ++ .../headless-payment-method-response.ts | 7 ++ .../payment/headless-payment-method-type.ts | 4 + .../src/payment/headless-payment-method.ts | 6 ++ .../payment/headless-payment-methods.mock.ts | 19 +++++ .../headless-payment-request-options.ts | 6 ++ packages/core/src/payment/index.ts | 5 ++ .../payment-method-request-sender.spec.ts | 46 ++++++++++- .../payment/payment-method-request-sender.ts | 79 +++++++++++++++++++ 10 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 packages/core/src/payment/headless-payment-method-config.ts create mode 100644 packages/core/src/payment/headless-payment-method-response.ts create mode 100644 packages/core/src/payment/headless-payment-method-type.ts create mode 100644 packages/core/src/payment/headless-payment-method.ts create mode 100644 packages/core/src/payment/headless-payment-methods.mock.ts create mode 100644 packages/core/src/payment/headless-payment-request-options.ts diff --git a/packages/core/src/common/http-request/responses.mock.ts b/packages/core/src/common/http-request/responses.mock.ts index 38e4fb873f..bf3192a25d 100644 --- a/packages/core/src/common/http-request/responses.mock.ts +++ b/packages/core/src/common/http-request/responses.mock.ts @@ -2,7 +2,8 @@ import { Response } from '@bigcommerce/request-sender'; import { ErrorResponseBody } from '@bigcommerce/checkout-sdk/payment-integration-api'; -import { PaymentResponse } from '../../payment'; +import { HeadlessPaymentMethodResponse, PaymentResponse } from '../../payment'; +import HeadlessPaymentMethod from '../../payment/headless-payment-method'; export function getResponse( body: T, @@ -38,6 +39,27 @@ export function getPaymentResponse( }; } +export function getHeadlessPaymentResponse( + site: HeadlessPaymentMethod, + headers = {}, + status = 200, + statusText = 'OK', +): Response> { + return { + body: { + data: { + site, + }, + }, + status, + statusText, + headers: { + 'content-type': 'application/json', + ...headers, + }, + }; +} + export function getErrorResponse( body = getErrorResponseBody(), headers = {}, diff --git a/packages/core/src/payment/headless-payment-method-config.ts b/packages/core/src/payment/headless-payment-method-config.ts new file mode 100644 index 0000000000..7b842a642c --- /dev/null +++ b/packages/core/src/payment/headless-payment-method-config.ts @@ -0,0 +1,8 @@ +import { HeadlessPaymentMethodType } from './headless-payment-method-type'; + +const HeadlessPaymentMethodConfig: Record = { + paypalcommerce: HeadlessPaymentMethodType.PAYPALCOMMERCE, + paypalcommercecredit: HeadlessPaymentMethodType.PAYPALCOMMERCECREDIT, +}; + +export default HeadlessPaymentMethodConfig; diff --git a/packages/core/src/payment/headless-payment-method-response.ts b/packages/core/src/payment/headless-payment-method-response.ts new file mode 100644 index 0000000000..ee4c05325b --- /dev/null +++ b/packages/core/src/payment/headless-payment-method-response.ts @@ -0,0 +1,7 @@ +import HeadlessPaymentMethod from './headless-payment-method'; + +export interface HeadlessPaymentMethodResponse { + data: { + site: HeadlessPaymentMethod; + }; +} diff --git a/packages/core/src/payment/headless-payment-method-type.ts b/packages/core/src/payment/headless-payment-method-type.ts new file mode 100644 index 0000000000..7d3a68a126 --- /dev/null +++ b/packages/core/src/payment/headless-payment-method-type.ts @@ -0,0 +1,4 @@ +export enum HeadlessPaymentMethodType { + PAYPALCOMMERCE = 'paypalcommerce.paypal', + PAYPALCOMMERCECREDIT = 'paypalcommerce.paypalcredit', +} diff --git a/packages/core/src/payment/headless-payment-method.ts b/packages/core/src/payment/headless-payment-method.ts new file mode 100644 index 0000000000..ceb852c29c --- /dev/null +++ b/packages/core/src/payment/headless-payment-method.ts @@ -0,0 +1,6 @@ +export default interface HeadlessPaymentMethod { + paymentWalletWithInitializationData: { + clientToken?: string; + initializationData?: T; + }; +} diff --git a/packages/core/src/payment/headless-payment-methods.mock.ts b/packages/core/src/payment/headless-payment-methods.mock.ts new file mode 100644 index 0000000000..b2c0068f80 --- /dev/null +++ b/packages/core/src/payment/headless-payment-methods.mock.ts @@ -0,0 +1,19 @@ +import HeadlessPaymentMethod from './headless-payment-method'; + +export const initializationData = { + merchantId: '100000', + paymentButtonStyles: { + checkoutTopButtonStyles: { color: 'blue', label: 'checkout', height: '36' }, + }, +}; + +export const encodedInitializationData = btoa(JSON.stringify(initializationData)); + +export function getHeadlessPaymentMethod(): HeadlessPaymentMethod { + return { + paymentWalletWithInitializationData: { + clientToken: 'clientToken', + initializationData: encodedInitializationData, + }, + }; +} diff --git a/packages/core/src/payment/headless-payment-request-options.ts b/packages/core/src/payment/headless-payment-request-options.ts new file mode 100644 index 0000000000..3d269a3f8d --- /dev/null +++ b/packages/core/src/payment/headless-payment-request-options.ts @@ -0,0 +1,6 @@ +import { RequestOptions } from '../common/http-request'; + +export default interface HeadlessPaymentRequestOptions extends RequestOptions { + body?: { query: string }; + headers: { Authorization: string; [key: string]: string }; +} diff --git a/packages/core/src/payment/index.ts b/packages/core/src/payment/index.ts index 03b86f6463..7739de2e2d 100644 --- a/packages/core/src/payment/index.ts +++ b/packages/core/src/payment/index.ts @@ -6,6 +6,7 @@ export { export * from './payment-method-actions'; export * from './payment-method-types'; export * from './payment-status-types'; +export * from './headless-payment-method-type'; export { default as PaymentAdditionalAction, @@ -37,12 +38,15 @@ export { WithMollieIssuerInstrument, } from './payment'; export { default as PaymentMethod } from './payment-method'; +export { default as HeadlessPaymentMethod } from './headless-payment-method'; export { default as PaymentMethodMeta } from './payment-method-meta'; export { default as PaymentMethodConfig } from './payment-method-config'; +export { default as HeadlessPaymentMethodConfig } from './headless-payment-method-config'; export { default as InitializationStrategy } from './payment-method-initialization-strategy'; export { default as PaymentMethodActionCreator } from './payment-method-action-creator'; export { default as paymentMethodReducer } from './payment-method-reducer'; export { default as PaymentMethodRequestSender } from './payment-method-request-sender'; +export { default as HeadlessPaymentRequestOptions } from './headless-payment-request-options'; export { default as PaymentMethodSelector, PaymentMethodSelectorFactory, @@ -55,6 +59,7 @@ export { default as PaymentRequestSender } from './payment-request-sender'; export { default as PaymentRequestTransformer } from './payment-request-transformer'; export { default as PaymentResponse } from './payment-response'; export { default as PaymentResponseBody } from './payment-response-body'; +export { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; export { default as PaymentSelector, PaymentSelectorFactory, diff --git a/packages/core/src/payment/payment-method-request-sender.spec.ts b/packages/core/src/payment/payment-method-request-sender.spec.ts index 430c14f5a0..1c736b7846 100644 --- a/packages/core/src/payment/payment-method-request-sender.spec.ts +++ b/packages/core/src/payment/payment-method-request-sender.spec.ts @@ -6,8 +6,10 @@ import { } from '@bigcommerce/request-sender'; import { ContentType, INTERNAL_USE_ONLY, SDK_VERSION_HEADERS } from '../common/http-request'; -import { getResponse } from '../common/http-request/responses.mock'; +import { getHeadlessPaymentResponse, getResponse } from '../common/http-request/responses.mock'; +import { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; +import { getHeadlessPaymentMethod, initializationData } from './headless-payment-methods.mock'; import PaymentMethod from './payment-method'; import PaymentMethodRequestSender from './payment-method-request-sender'; import { getPaymentMethod, getPaymentMethods } from './payment-methods.mock'; @@ -136,4 +138,46 @@ describe('PaymentMethodRequestSender', () => { }); }); }); + + describe('#loadPaymentWalletWithInitializationData()', () => { + let response: Response; + const authorization = 'authorization-1234'; + + beforeEach(() => { + response = getHeadlessPaymentResponse(getHeadlessPaymentMethod()); + jest.spyOn(requestSender, 'post').mockReturnValue(Promise.resolve(response)); + }); + + it('loads headless payment method', async () => { + const walletInitData = + await paymentMethodRequestSender.loadPaymentWalletWithInitializationData( + 'paypalcommerce', + { headers: { Authorization: authorization } }, + ); + + expect(requestSender.post).toHaveBeenCalledWith( + '/graphql', + expect.objectContaining({ + headers: { + Authorization: authorization, + 'Content-Type': 'application/json', + }, + }), + ); + + expect(walletInitData).toEqual( + expect.objectContaining({ + body: { + initializationData, + clientToken: 'clientToken', + id: 'paypalcommerce', + config: {}, + method: '', + supportedCards: [], + type: 'PAYMENT_TYPE_API', + }, + }), + ); + }); + }); }); diff --git a/packages/core/src/payment/payment-method-request-sender.ts b/packages/core/src/payment/payment-method-request-sender.ts index b0fea224e5..6b957453c6 100644 --- a/packages/core/src/payment/payment-method-request-sender.ts +++ b/packages/core/src/payment/payment-method-request-sender.ts @@ -7,6 +7,10 @@ import { SDK_VERSION_HEADERS, } from '../common/http-request'; +import HeadlessPaymentMethodConfig from './headless-payment-method-config'; +import { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; +import { HeadlessPaymentMethodType } from './headless-payment-method-type'; +import HeadlessPaymentRequestOptions from './headless-payment-request-options'; import PaymentMethod from './payment-method'; export default class PaymentMethodRequestSender { @@ -44,4 +48,79 @@ export default class PaymentMethodRequestSender { params, }); } + + /** + * GraphQL payment requests + */ + loadPaymentWalletWithInitializationData( + methodId: string, + options: HeadlessPaymentRequestOptions, + ): Promise> { + const url = `/graphql`; + + const entityId = this.getPaymentEntityId(methodId); + + const graphQLQuery = ` + query { + site { + paymentWalletWithInitializationData(filter: {paymentWalletEntityId: "${entityId}"}) { + clientToken + initializationData + } + } + } + `; + + const requestOptions: HeadlessPaymentRequestOptions = { + headers: { + ...options.headers, + 'Content-Type': 'application/json', + }, + body: { + query: graphQLQuery, + }, + }; + + return this._requestSender + .post>(url, requestOptions) + .then((response) => this.transformToPaymentMethodResponse(response, methodId)); + } + + private transformToPaymentMethodResponse( + response: Response, + methodId: string, + ): Response { + const { + body: { + data: { + site: { paymentWalletWithInitializationData }, + }, + }, + } = response; + + return { + ...response, + body: { + initializationData: JSON.parse( + atob(paymentWalletWithInitializationData.initializationData), + ), + clientToken: paymentWalletWithInitializationData.clientToken, + id: methodId, + config: {}, + method: '', + supportedCards: [], + type: 'PAYMENT_TYPE_API', + }, + }; + } + + private getPaymentEntityId(methodId: string): HeadlessPaymentMethodType { + const entityId = HeadlessPaymentMethodConfig[methodId]; + + if (!entityId) { + throw new Error('Unable to get payment entity id.'); + } + + return entityId; + } } From 508e9652724f85da0833e9f9fafeaa091df75113 Mon Sep 17 00:00:00 2001 From: bc-nick Date: Thu, 19 Dec 2024 10:15:55 +0100 Subject: [PATCH 2/6] feat(payment): PAYPAL-4937 updated interface --- .../core/src/common/http-request/responses.mock.ts | 6 +++--- .../payment/headless-payment-method-response.ts | 4 ++-- .../core/src/payment/headless-payment-method.ts | 5 +++-- .../src/payment/payment-method-request-sender.ts | 14 ++++++++------ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/core/src/common/http-request/responses.mock.ts b/packages/core/src/common/http-request/responses.mock.ts index bf3192a25d..dc4929dc28 100644 --- a/packages/core/src/common/http-request/responses.mock.ts +++ b/packages/core/src/common/http-request/responses.mock.ts @@ -39,12 +39,12 @@ export function getPaymentResponse( }; } -export function getHeadlessPaymentResponse( - site: HeadlessPaymentMethod, +export function getHeadlessPaymentResponse( + site: HeadlessPaymentMethod, headers = {}, status = 200, statusText = 'OK', -): Response> { +): Response { return { body: { data: { diff --git a/packages/core/src/payment/headless-payment-method-response.ts b/packages/core/src/payment/headless-payment-method-response.ts index ee4c05325b..0b72c500f4 100644 --- a/packages/core/src/payment/headless-payment-method-response.ts +++ b/packages/core/src/payment/headless-payment-method-response.ts @@ -1,7 +1,7 @@ import HeadlessPaymentMethod from './headless-payment-method'; -export interface HeadlessPaymentMethodResponse { +export interface HeadlessPaymentMethodResponse { data: { - site: HeadlessPaymentMethod; + site: HeadlessPaymentMethod; }; } diff --git a/packages/core/src/payment/headless-payment-method.ts b/packages/core/src/payment/headless-payment-method.ts index ceb852c29c..ec5131a003 100644 --- a/packages/core/src/payment/headless-payment-method.ts +++ b/packages/core/src/payment/headless-payment-method.ts @@ -1,6 +1,7 @@ -export default interface HeadlessPaymentMethod { +export default interface HeadlessPaymentMethod { paymentWalletWithInitializationData: { clientToken?: string; - initializationData?: T; + // INFO:: initializationData given in base64 format + initializationData?: string; }; } diff --git a/packages/core/src/payment/payment-method-request-sender.ts b/packages/core/src/payment/payment-method-request-sender.ts index 6b957453c6..98c42c767f 100644 --- a/packages/core/src/payment/payment-method-request-sender.ts +++ b/packages/core/src/payment/payment-method-request-sender.ts @@ -82,7 +82,7 @@ export default class PaymentMethodRequestSender { }; return this._requestSender - .post>(url, requestOptions) + .post(url, requestOptions) .then((response) => this.transformToPaymentMethodResponse(response, methodId)); } @@ -93,7 +93,9 @@ export default class PaymentMethodRequestSender { const { body: { data: { - site: { paymentWalletWithInitializationData }, + site: { + paymentWalletWithInitializationData: { clientToken, initializationData }, + }, }, }, } = response; @@ -101,10 +103,10 @@ export default class PaymentMethodRequestSender { return { ...response, body: { - initializationData: JSON.parse( - atob(paymentWalletWithInitializationData.initializationData), - ), - clientToken: paymentWalletWithInitializationData.clientToken, + initializationData: initializationData + ? JSON.parse(atob(initializationData)) + : null, + clientToken, id: methodId, config: {}, method: '', From 7afaa0fa1c2192afe73d49c1af2b1197c1ef0770 Mon Sep 17 00:00:00 2001 From: bc-nick Date: Mon, 23 Dec 2024 15:17:19 +0100 Subject: [PATCH 3/6] feat(payment): PAYPAL-4937 updates after review --- .../core/src/common/http-request/responses.mock.ts | 2 +- .../src/payment/headless-payment-methods.mock.ts | 2 +- .../headless-payment-method-config.ts | 0 .../headless-payment-method-response.ts | 0 .../headless-payment-method-type.ts | 0 .../headless-payment-method.ts | 0 .../headless-payment-request-options.ts | 2 +- .../core/src/payment/headless-payment/index.ts | 6 ++++++ packages/core/src/payment/index.ts | 11 ++++++----- .../payment/payment-method-request-sender.spec.ts | 2 +- .../src/payment/payment-method-request-sender.ts | 14 +++++++------- 11 files changed, 23 insertions(+), 16 deletions(-) rename packages/core/src/payment/{ => headless-payment}/headless-payment-method-config.ts (100%) rename packages/core/src/payment/{ => headless-payment}/headless-payment-method-response.ts (100%) rename packages/core/src/payment/{ => headless-payment}/headless-payment-method-type.ts (100%) rename packages/core/src/payment/{ => headless-payment}/headless-payment-method.ts (100%) rename packages/core/src/payment/{ => headless-payment}/headless-payment-request-options.ts (74%) create mode 100644 packages/core/src/payment/headless-payment/index.ts diff --git a/packages/core/src/common/http-request/responses.mock.ts b/packages/core/src/common/http-request/responses.mock.ts index dc4929dc28..5c28084f6f 100644 --- a/packages/core/src/common/http-request/responses.mock.ts +++ b/packages/core/src/common/http-request/responses.mock.ts @@ -3,7 +3,7 @@ import { Response } from '@bigcommerce/request-sender'; import { ErrorResponseBody } from '@bigcommerce/checkout-sdk/payment-integration-api'; import { HeadlessPaymentMethodResponse, PaymentResponse } from '../../payment'; -import HeadlessPaymentMethod from '../../payment/headless-payment-method'; +import { HeadlessPaymentMethod } from '../../payment/headless-payment'; export function getResponse( body: T, diff --git a/packages/core/src/payment/headless-payment-methods.mock.ts b/packages/core/src/payment/headless-payment-methods.mock.ts index b2c0068f80..a5abc372ee 100644 --- a/packages/core/src/payment/headless-payment-methods.mock.ts +++ b/packages/core/src/payment/headless-payment-methods.mock.ts @@ -1,4 +1,4 @@ -import HeadlessPaymentMethod from './headless-payment-method'; +import { HeadlessPaymentMethod } from './headless-payment'; export const initializationData = { merchantId: '100000', diff --git a/packages/core/src/payment/headless-payment-method-config.ts b/packages/core/src/payment/headless-payment/headless-payment-method-config.ts similarity index 100% rename from packages/core/src/payment/headless-payment-method-config.ts rename to packages/core/src/payment/headless-payment/headless-payment-method-config.ts diff --git a/packages/core/src/payment/headless-payment-method-response.ts b/packages/core/src/payment/headless-payment/headless-payment-method-response.ts similarity index 100% rename from packages/core/src/payment/headless-payment-method-response.ts rename to packages/core/src/payment/headless-payment/headless-payment-method-response.ts diff --git a/packages/core/src/payment/headless-payment-method-type.ts b/packages/core/src/payment/headless-payment/headless-payment-method-type.ts similarity index 100% rename from packages/core/src/payment/headless-payment-method-type.ts rename to packages/core/src/payment/headless-payment/headless-payment-method-type.ts diff --git a/packages/core/src/payment/headless-payment-method.ts b/packages/core/src/payment/headless-payment/headless-payment-method.ts similarity index 100% rename from packages/core/src/payment/headless-payment-method.ts rename to packages/core/src/payment/headless-payment/headless-payment-method.ts diff --git a/packages/core/src/payment/headless-payment-request-options.ts b/packages/core/src/payment/headless-payment/headless-payment-request-options.ts similarity index 74% rename from packages/core/src/payment/headless-payment-request-options.ts rename to packages/core/src/payment/headless-payment/headless-payment-request-options.ts index 3d269a3f8d..224a8f7a48 100644 --- a/packages/core/src/payment/headless-payment-request-options.ts +++ b/packages/core/src/payment/headless-payment/headless-payment-request-options.ts @@ -1,4 +1,4 @@ -import { RequestOptions } from '../common/http-request'; +import { RequestOptions } from '../../common/http-request'; export default interface HeadlessPaymentRequestOptions extends RequestOptions { body?: { query: string }; diff --git a/packages/core/src/payment/headless-payment/index.ts b/packages/core/src/payment/headless-payment/index.ts new file mode 100644 index 0000000000..f43c3626ea --- /dev/null +++ b/packages/core/src/payment/headless-payment/index.ts @@ -0,0 +1,6 @@ +export { default as HeadlessPaymentMethod } from './headless-payment-method'; +export { default as HeadlessPaymentMethodConfig } from './headless-payment-method-config'; +export { default as HeadlessPaymentRequestOptions } from './headless-payment-request-options'; + +export { HeadlessPaymentMethodType } from './headless-payment-method-type'; +export { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; diff --git a/packages/core/src/payment/index.ts b/packages/core/src/payment/index.ts index 7739de2e2d..9c1e295ff8 100644 --- a/packages/core/src/payment/index.ts +++ b/packages/core/src/payment/index.ts @@ -6,7 +6,6 @@ export { export * from './payment-method-actions'; export * from './payment-method-types'; export * from './payment-status-types'; -export * from './headless-payment-method-type'; export { default as PaymentAdditionalAction, @@ -19,6 +18,12 @@ export { default as isHostedInstrumentLike } from './is-hosted-intrument-like'; export { default as isNonceLike } from './is-nonce-like'; export { default as isVaultedInstrument } from './is-vaulted-instrument'; export { default as PaymentActionCreator } from './payment-action-creator'; +export { + HeadlessPaymentMethod, + HeadlessPaymentMethodConfig, + HeadlessPaymentRequestOptions, + HeadlessPaymentMethodResponse, +} from './headless-payment'; export { default as Payment, CreditCardInstrument, @@ -38,15 +43,12 @@ export { WithMollieIssuerInstrument, } from './payment'; export { default as PaymentMethod } from './payment-method'; -export { default as HeadlessPaymentMethod } from './headless-payment-method'; export { default as PaymentMethodMeta } from './payment-method-meta'; export { default as PaymentMethodConfig } from './payment-method-config'; -export { default as HeadlessPaymentMethodConfig } from './headless-payment-method-config'; export { default as InitializationStrategy } from './payment-method-initialization-strategy'; export { default as PaymentMethodActionCreator } from './payment-method-action-creator'; export { default as paymentMethodReducer } from './payment-method-reducer'; export { default as PaymentMethodRequestSender } from './payment-method-request-sender'; -export { default as HeadlessPaymentRequestOptions } from './headless-payment-request-options'; export { default as PaymentMethodSelector, PaymentMethodSelectorFactory, @@ -59,7 +61,6 @@ export { default as PaymentRequestSender } from './payment-request-sender'; export { default as PaymentRequestTransformer } from './payment-request-transformer'; export { default as PaymentResponse } from './payment-response'; export { default as PaymentResponseBody } from './payment-response-body'; -export { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; export { default as PaymentSelector, PaymentSelectorFactory, diff --git a/packages/core/src/payment/payment-method-request-sender.spec.ts b/packages/core/src/payment/payment-method-request-sender.spec.ts index 1c736b7846..29740457b1 100644 --- a/packages/core/src/payment/payment-method-request-sender.spec.ts +++ b/packages/core/src/payment/payment-method-request-sender.spec.ts @@ -8,7 +8,7 @@ import { import { ContentType, INTERNAL_USE_ONLY, SDK_VERSION_HEADERS } from '../common/http-request'; import { getHeadlessPaymentResponse, getResponse } from '../common/http-request/responses.mock'; -import { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; +import { HeadlessPaymentMethodResponse } from './headless-payment'; import { getHeadlessPaymentMethod, initializationData } from './headless-payment-methods.mock'; import PaymentMethod from './payment-method'; import PaymentMethodRequestSender from './payment-method-request-sender'; diff --git a/packages/core/src/payment/payment-method-request-sender.ts b/packages/core/src/payment/payment-method-request-sender.ts index 98c42c767f..8411202e8a 100644 --- a/packages/core/src/payment/payment-method-request-sender.ts +++ b/packages/core/src/payment/payment-method-request-sender.ts @@ -7,10 +7,12 @@ import { SDK_VERSION_HEADERS, } from '../common/http-request'; -import HeadlessPaymentMethodConfig from './headless-payment-method-config'; -import { HeadlessPaymentMethodResponse } from './headless-payment-method-response'; -import { HeadlessPaymentMethodType } from './headless-payment-method-type'; -import HeadlessPaymentRequestOptions from './headless-payment-request-options'; +import { + HeadlessPaymentMethodConfig, + HeadlessPaymentMethodResponse, + HeadlessPaymentMethodType, + HeadlessPaymentRequestOptions, +} from './headless-payment'; import PaymentMethod from './payment-method'; export default class PaymentMethodRequestSender { @@ -56,8 +58,6 @@ export default class PaymentMethodRequestSender { methodId: string, options: HeadlessPaymentRequestOptions, ): Promise> { - const url = `/graphql`; - const entityId = this.getPaymentEntityId(methodId); const graphQLQuery = ` @@ -82,7 +82,7 @@ export default class PaymentMethodRequestSender { }; return this._requestSender - .post(url, requestOptions) + .post('/graphql', requestOptions) .then((response) => this.transformToPaymentMethodResponse(response, methodId)); } From 01ba96692b4e9d1942ba9e277c59855c7f2c627f Mon Sep 17 00:00:00 2001 From: bc-nick Date: Tue, 24 Dec 2024 11:56:43 +0100 Subject: [PATCH 4/6] feat(payment): PAYPAL-4937 updates after review --- .../payment/payment-method-request-sender.ts | 39 +++---------------- .../src/payment/payment-method-transformer.ts | 32 +++++++++++++++ 2 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 packages/core/src/payment/payment-method-transformer.ts diff --git a/packages/core/src/payment/payment-method-request-sender.ts b/packages/core/src/payment/payment-method-request-sender.ts index 8411202e8a..df5eb921bf 100644 --- a/packages/core/src/payment/payment-method-request-sender.ts +++ b/packages/core/src/payment/payment-method-request-sender.ts @@ -14,6 +14,7 @@ import { HeadlessPaymentRequestOptions, } from './headless-payment'; import PaymentMethod from './payment-method'; +import paymentMethodTransformer from './payment-method-transformer'; export default class PaymentMethodRequestSender { constructor(private _requestSender: RequestSender) {} @@ -58,12 +59,12 @@ export default class PaymentMethodRequestSender { methodId: string, options: HeadlessPaymentRequestOptions, ): Promise> { - const entityId = this.getPaymentEntityId(methodId); + const entityId = this._getPaymentEntityId(methodId); const graphQLQuery = ` query { site { - paymentWalletWithInitializationData(filter: {paymentWalletEntityId: "${entityId}"}) { + paymentWalletWithInitializationData(filter: { paymentWalletEntityId: "${entityId}" }) { clientToken initializationData } @@ -83,40 +84,10 @@ export default class PaymentMethodRequestSender { return this._requestSender .post('/graphql', requestOptions) - .then((response) => this.transformToPaymentMethodResponse(response, methodId)); + .then((response) => paymentMethodTransformer(response, methodId)); } - private transformToPaymentMethodResponse( - response: Response, - methodId: string, - ): Response { - const { - body: { - data: { - site: { - paymentWalletWithInitializationData: { clientToken, initializationData }, - }, - }, - }, - } = response; - - return { - ...response, - body: { - initializationData: initializationData - ? JSON.parse(atob(initializationData)) - : null, - clientToken, - id: methodId, - config: {}, - method: '', - supportedCards: [], - type: 'PAYMENT_TYPE_API', - }, - }; - } - - private getPaymentEntityId(methodId: string): HeadlessPaymentMethodType { + private _getPaymentEntityId(methodId: string): HeadlessPaymentMethodType { const entityId = HeadlessPaymentMethodConfig[methodId]; if (!entityId) { diff --git a/packages/core/src/payment/payment-method-transformer.ts b/packages/core/src/payment/payment-method-transformer.ts new file mode 100644 index 0000000000..17f9e8b4bd --- /dev/null +++ b/packages/core/src/payment/payment-method-transformer.ts @@ -0,0 +1,32 @@ +import { Response } from '@bigcommerce/request-sender'; + +import { HeadlessPaymentMethodResponse } from './headless-payment'; +import PaymentMethod from './payment-method'; + +export default function paymentMethodTransformer( + response: Response, + methodId: string, +): Response { + const { + body: { + data: { + site: { + paymentWalletWithInitializationData: { clientToken, initializationData }, + }, + }, + }, + } = response; + + return { + ...response, + body: { + initializationData: initializationData ? JSON.parse(atob(initializationData)) : null, + clientToken, + id: methodId, + config: {}, + method: '', + supportedCards: [], + type: 'PAYMENT_TYPE_API', + }, + }; +} From a14e11bf72233ac07a2f1b157a5cc062469e01e4 Mon Sep 17 00:00:00 2001 From: bc-nick Date: Tue, 7 Jan 2025 16:44:14 +0100 Subject: [PATCH 5/6] feat(payment): PAYPAL-4937 added loadPaymentWalletWithInitializationData method --- packages/core/src/config/config-selector.ts | 7 + packages/core/src/config/config-state.ts | 1 + .../create-payment-integration-selectors.ts | 2 + .../headless-payment-method-config.ts | 1 + .../headless-payment-method-type.ts | 1 + .../payment-method-action-creator.spec.ts | 135 ++++++++++++++++++ .../payment/payment-method-action-creator.ts | 51 +++++++ .../src/payment-integration-selectors.ts | 2 + .../payment-integration-service.mock.ts | 1 + 9 files changed, 201 insertions(+) diff --git a/packages/core/src/config/config-selector.ts b/packages/core/src/config/config-selector.ts index b1f94f4244..eb8830834c 100644 --- a/packages/core/src/config/config-selector.ts +++ b/packages/core/src/config/config-selector.ts @@ -18,6 +18,7 @@ export default interface ConfigSelector { getHost(): string | undefined; getLocale(): string | undefined; getVariantIdentificationToken(): string | undefined; + getStorefrontJwtToken(): string | undefined; getLoadError(): Error | undefined; isLoading(): boolean; } @@ -56,6 +57,11 @@ export function createConfigSelectorFactory(): ConfigSelectorFactory { }, ); + const getStorefrontJwtToken = createSelector( + (state: ConfigState) => state.meta && state.meta.storefrontJwtToken, + (data) => () => data, + ); + const getStoreConfig = createSelector( (state: ConfigState) => state.data, (_: ConfigState, { formState }: ConfigSelectorDependencies) => formState && formState.data, @@ -120,6 +126,7 @@ export function createConfigSelectorFactory(): ConfigSelectorFactory { getContextConfig: getContextConfig(state), getExternalSource: getExternalSource(state), getHost: getHost(state), + getStorefrontJwtToken: getStorefrontJwtToken(state), getLocale: getLocale(state), getVariantIdentificationToken: getVariantIdentificationToken(state), getLoadError: getLoadError(state), diff --git a/packages/core/src/config/config-state.ts b/packages/core/src/config/config-state.ts index 15ded51e82..7a39cccc98 100644 --- a/packages/core/src/config/config-state.ts +++ b/packages/core/src/config/config-state.ts @@ -12,6 +12,7 @@ export interface ConfigMetaState { variantIdentificationToken?: string; host?: string; locale?: string; + storefrontJwtToken?: string; } export interface ConfigErrorsState { diff --git a/packages/core/src/payment-integration/create-payment-integration-selectors.ts b/packages/core/src/payment-integration/create-payment-integration-selectors.ts index 5a1711fcb1..08b454851d 100644 --- a/packages/core/src/payment-integration/create-payment-integration-selectors.ts +++ b/packages/core/src/payment-integration/create-payment-integration-selectors.ts @@ -14,6 +14,7 @@ export default function createPaymentIntegrationSelectors({ getStoreConfig, getStoreConfigOrThrow, getConfig, + getStorefrontJwtToken, }, consignments: { getConsignments, getConsignmentsOrThrow }, countries: { getCountries }, @@ -80,6 +81,7 @@ export default function createPaymentIntegrationSelectors({ getPaymentStatusOrThrow, getPaymentRedirectUrl, getPaymentRedirectUrlOrThrow, + getStorefrontJwtToken, getPaymentMethod: clone(getPaymentMethod), getPaymentMethodOrThrow: clone(getPaymentMethodOrThrow), getPaymentMethodsMeta: clone(getPaymentMethodsMeta), diff --git a/packages/core/src/payment/headless-payment/headless-payment-method-config.ts b/packages/core/src/payment/headless-payment/headless-payment-method-config.ts index 7b842a642c..cc501bd24d 100644 --- a/packages/core/src/payment/headless-payment/headless-payment-method-config.ts +++ b/packages/core/src/payment/headless-payment/headless-payment-method-config.ts @@ -3,6 +3,7 @@ import { HeadlessPaymentMethodType } from './headless-payment-method-type'; const HeadlessPaymentMethodConfig: Record = { paypalcommerce: HeadlessPaymentMethodType.PAYPALCOMMERCE, paypalcommercecredit: HeadlessPaymentMethodType.PAYPALCOMMERCECREDIT, + braintree: HeadlessPaymentMethodType.BRAINTREE, }; export default HeadlessPaymentMethodConfig; diff --git a/packages/core/src/payment/headless-payment/headless-payment-method-type.ts b/packages/core/src/payment/headless-payment/headless-payment-method-type.ts index 7d3a68a126..734e4eca81 100644 --- a/packages/core/src/payment/headless-payment/headless-payment-method-type.ts +++ b/packages/core/src/payment/headless-payment/headless-payment-method-type.ts @@ -1,4 +1,5 @@ export enum HeadlessPaymentMethodType { PAYPALCOMMERCE = 'paypalcommerce.paypal', PAYPALCOMMERCECREDIT = 'paypalcommerce.paypalcredit', + BRAINTREE = 'braintree.paypal', } diff --git a/packages/core/src/payment/payment-method-action-creator.spec.ts b/packages/core/src/payment/payment-method-action-creator.spec.ts index cb1742d73f..4eba1c7767 100644 --- a/packages/core/src/payment/payment-method-action-creator.spec.ts +++ b/packages/core/src/payment/payment-method-action-creator.spec.ts @@ -42,7 +42,16 @@ describe('PaymentMethodActionCreator', () => { Promise.resolve(paymentMethodsResponse), ); + jest.spyOn( + paymentMethodRequestSender, + 'loadPaymentWalletWithInitializationData', + ).mockReturnValue(Promise.resolve(paymentMethodResponse)); + jest.spyOn(store.getState().cart, 'getCartOrThrow').mockReturnValue(getCheckout().cart); + + jest.spyOn(store.getState().config, 'getStorefrontJwtToken').mockReturnValue( + 'storefront_jwt_token', + ); }); describe('#loadPaymentMethods()', () => { @@ -195,6 +204,132 @@ describe('PaymentMethodActionCreator', () => { }); }); + describe('#loadPaymentWalletWithInitializationData()', () => { + it('loads payment wallet method', async () => { + const methodId = 'braintree'; + + await from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData(methodId)(store), + ).toPromise(); + + expect( + paymentMethodRequestSender.loadPaymentWalletWithInitializationData, + ).toHaveBeenCalledWith(methodId, { + headers: { + Authorization: `Bearer storefront_jwt_token`, + 'Content-Type': 'application/json', + }, + }); + }); + + it('loads payment wallet method with timeout', async () => { + const methodId = 'braintree'; + const options = { + timeout: createTimeout(), + }; + + await from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData( + methodId, + options, + )(store), + ).toPromise(); + + expect( + paymentMethodRequestSender.loadPaymentWalletWithInitializationData, + ).toHaveBeenCalledWith(methodId, { + headers: { + Authorization: `Bearer storefront_jwt_token`, + 'Content-Type': 'application/json', + }, + ...options, + }); + }); + + it('emits actions if able to load payment wallet method', async () => { + const methodId = 'braintree'; + const actions = await from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData(methodId)(store), + ) + .pipe(toArray()) + .toPromise(); + + expect(actions).toEqual([ + { type: PaymentMethodActionType.LoadPaymentMethodRequested, meta: { methodId } }, + { + type: PaymentMethodActionType.LoadPaymentMethodSucceeded, + meta: { methodId }, + payload: paymentMethodResponse.body, + }, + ]); + }); + + it('emits actions with cached values if available', async () => { + const methodId = 'braintree'; + const options = { useCache: true }; + const actions = await merge( + from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData( + methodId, + options, + )(store), + ), + from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData( + methodId, + options, + )(store), + ), + ) + .pipe(toArray()) + .toPromise(); + + expect( + paymentMethodRequestSender.loadPaymentWalletWithInitializationData, + ).toHaveBeenCalledTimes(1); + expect(actions).toEqual([ + { type: PaymentMethodActionType.LoadPaymentMethodRequested, meta: { methodId } }, + { type: PaymentMethodActionType.LoadPaymentMethodRequested, meta: { methodId } }, + { + type: PaymentMethodActionType.LoadPaymentMethodSucceeded, + meta: { methodId }, + payload: paymentMethodResponse.body, + }, + { + type: PaymentMethodActionType.LoadPaymentMethodSucceeded, + meta: { methodId }, + payload: paymentMethodResponse.body, + }, + ]); + }); + + it('emits error actions if unable to load payment wallet method', async () => { + jest.spyOn( + paymentMethodRequestSender, + 'loadPaymentWalletWithInitializationData', + ).mockReturnValue(Promise.reject(errorResponse)); + + const methodId = 'braintree'; + const errorHandler = jest.fn((action) => of(action)); + const actions = await from( + paymentMethodActionCreator.loadPaymentWalletWithInitializationData(methodId)(store), + ) + .pipe(catchError(errorHandler), toArray()) + .toPromise(); + + expect(errorHandler).toHaveBeenCalled(); + expect(actions).toEqual([ + { type: PaymentMethodActionType.LoadPaymentMethodRequested, meta: { methodId } }, + { + type: PaymentMethodActionType.LoadPaymentMethodFailed, + meta: { methodId }, + payload: errorResponse, + error: true, + }, + ]); + }); + }); + describe('#loadPaymentMethodsByIds()', () => { it('loads payment methods data', async () => { const methodId = 'braintree'; diff --git a/packages/core/src/payment/payment-method-action-creator.ts b/packages/core/src/payment/payment-method-action-creator.ts index 68997b3fa6..4355c73d7e 100644 --- a/packages/core/src/payment/payment-method-action-creator.ts +++ b/packages/core/src/payment/payment-method-action-creator.ts @@ -4,6 +4,7 @@ import { Observable, Observer } from 'rxjs'; import { InternalCheckoutSelectors } from '../checkout'; import { ActionOptions, cachableAction } from '../common/data-store'; +import { MissingDataError, MissingDataErrorType } from '../common/error/errors'; import { RequestOptions } from '../common/http-request'; import { @@ -160,6 +161,56 @@ export default class PaymentMethodActionCreator { }); } + @cachableAction + loadPaymentWalletWithInitializationData( + methodId: string, + options?: RequestOptions & ActionOptions, + ): ThunkAction { + return (store) => + Observable.create((observer: Observer) => { + const state = store.getState(); + const jwtToken = state.config.getStorefrontJwtToken(); + + if (!jwtToken) { + throw new MissingDataError(MissingDataErrorType.MissingPaymentToken); + } + + observer.next( + createAction(PaymentMethodActionType.LoadPaymentMethodRequested, undefined, { + methodId, + }), + ); + + this._requestSender + .loadPaymentWalletWithInitializationData(methodId, { + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + ...options, + }) + .then((response) => { + observer.next( + createAction( + PaymentMethodActionType.LoadPaymentMethodSucceeded, + response.body, + { methodId }, + ), + ); + observer.complete(); + }) + .catch((response) => { + observer.error( + createErrorAction( + PaymentMethodActionType.LoadPaymentMethodFailed, + response, + { methodId }, + ), + ); + }); + }); + } + private _filterApplePay(methods: PaymentMethod[]): PaymentMethod[] { return filter(methods, (method) => { if (method.id === APPLEPAYID && !isApplePayWindow(window)) { diff --git a/packages/payment-integration-api/src/payment-integration-selectors.ts b/packages/payment-integration-api/src/payment-integration-selectors.ts index a75d417cdc..5f6564f08a 100644 --- a/packages/payment-integration-api/src/payment-integration-selectors.ts +++ b/packages/payment-integration-api/src/payment-integration-selectors.ts @@ -85,6 +85,8 @@ export default interface PaymentIntegrationSelectors { getInstrumentsMeta(): InstrumentMeta | undefined; + getStorefrontJwtToken(): string | undefined; + getOrderMeta(): OrderMetaState | undefined; getPaymentMethodsMeta(): PaymentMethodMeta | undefined; diff --git a/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts b/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts index 5bd6cad0fe..c7deac7aed 100644 --- a/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts +++ b/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts @@ -59,6 +59,7 @@ const state = { getPaymentRedirectUrl: jest.fn(), getPaymentRedirectUrlOrThrow: jest.fn(), isPaymentDataRequired: jest.fn(), + getStorefrontJwtToken: jest.fn(), }; const createBuyNowCart = jest.fn(() => Promise.resolve(getCart())); From 98337a410717bb4a045289bf4f50da1fc0a0787e Mon Sep 17 00:00:00 2001 From: bc-nick Date: Wed, 26 Feb 2025 22:58:54 +0100 Subject: [PATCH 6/6] feat(payment): PAYPAL-4937 updates related to new requirements --- packages/core/src/config/config-selector.ts | 7 ----- packages/core/src/config/config-state.ts | 1 - .../create-payment-integration-selectors.ts | 2 -- .../headless-payment-request-options.ts | 3 +- .../payment-method-action-creator.spec.ts | 19 ++---------- .../payment/payment-method-action-creator.ts | 15 ++-------- .../payment-method-request-sender.spec.ts | 13 ++++---- .../payment/payment-method-request-sender.ts | 30 ++++++------------- .../src/payment-integration-selectors.ts | 2 -- .../payment-integration-service.mock.ts | 1 - 10 files changed, 21 insertions(+), 72 deletions(-) diff --git a/packages/core/src/config/config-selector.ts b/packages/core/src/config/config-selector.ts index eb8830834c..b1f94f4244 100644 --- a/packages/core/src/config/config-selector.ts +++ b/packages/core/src/config/config-selector.ts @@ -18,7 +18,6 @@ export default interface ConfigSelector { getHost(): string | undefined; getLocale(): string | undefined; getVariantIdentificationToken(): string | undefined; - getStorefrontJwtToken(): string | undefined; getLoadError(): Error | undefined; isLoading(): boolean; } @@ -57,11 +56,6 @@ export function createConfigSelectorFactory(): ConfigSelectorFactory { }, ); - const getStorefrontJwtToken = createSelector( - (state: ConfigState) => state.meta && state.meta.storefrontJwtToken, - (data) => () => data, - ); - const getStoreConfig = createSelector( (state: ConfigState) => state.data, (_: ConfigState, { formState }: ConfigSelectorDependencies) => formState && formState.data, @@ -126,7 +120,6 @@ export function createConfigSelectorFactory(): ConfigSelectorFactory { getContextConfig: getContextConfig(state), getExternalSource: getExternalSource(state), getHost: getHost(state), - getStorefrontJwtToken: getStorefrontJwtToken(state), getLocale: getLocale(state), getVariantIdentificationToken: getVariantIdentificationToken(state), getLoadError: getLoadError(state), diff --git a/packages/core/src/config/config-state.ts b/packages/core/src/config/config-state.ts index 7a39cccc98..15ded51e82 100644 --- a/packages/core/src/config/config-state.ts +++ b/packages/core/src/config/config-state.ts @@ -12,7 +12,6 @@ export interface ConfigMetaState { variantIdentificationToken?: string; host?: string; locale?: string; - storefrontJwtToken?: string; } export interface ConfigErrorsState { diff --git a/packages/core/src/payment-integration/create-payment-integration-selectors.ts b/packages/core/src/payment-integration/create-payment-integration-selectors.ts index 08b454851d..5a1711fcb1 100644 --- a/packages/core/src/payment-integration/create-payment-integration-selectors.ts +++ b/packages/core/src/payment-integration/create-payment-integration-selectors.ts @@ -14,7 +14,6 @@ export default function createPaymentIntegrationSelectors({ getStoreConfig, getStoreConfigOrThrow, getConfig, - getStorefrontJwtToken, }, consignments: { getConsignments, getConsignmentsOrThrow }, countries: { getCountries }, @@ -81,7 +80,6 @@ export default function createPaymentIntegrationSelectors({ getPaymentStatusOrThrow, getPaymentRedirectUrl, getPaymentRedirectUrlOrThrow, - getStorefrontJwtToken, getPaymentMethod: clone(getPaymentMethod), getPaymentMethodOrThrow: clone(getPaymentMethodOrThrow), getPaymentMethodsMeta: clone(getPaymentMethodsMeta), diff --git a/packages/core/src/payment/headless-payment/headless-payment-request-options.ts b/packages/core/src/payment/headless-payment/headless-payment-request-options.ts index 224a8f7a48..9f9dfd5dfa 100644 --- a/packages/core/src/payment/headless-payment/headless-payment-request-options.ts +++ b/packages/core/src/payment/headless-payment/headless-payment-request-options.ts @@ -1,6 +1,5 @@ import { RequestOptions } from '../../common/http-request'; export default interface HeadlessPaymentRequestOptions extends RequestOptions { - body?: { query: string }; - headers: { Authorization: string; [key: string]: string }; + body: { entityId: string }; } diff --git a/packages/core/src/payment/payment-method-action-creator.spec.ts b/packages/core/src/payment/payment-method-action-creator.spec.ts index 4eba1c7767..81146e85af 100644 --- a/packages/core/src/payment/payment-method-action-creator.spec.ts +++ b/packages/core/src/payment/payment-method-action-creator.spec.ts @@ -48,10 +48,6 @@ describe('PaymentMethodActionCreator', () => { ).mockReturnValue(Promise.resolve(paymentMethodResponse)); jest.spyOn(store.getState().cart, 'getCartOrThrow').mockReturnValue(getCheckout().cart); - - jest.spyOn(store.getState().config, 'getStorefrontJwtToken').mockReturnValue( - 'storefront_jwt_token', - ); }); describe('#loadPaymentMethods()', () => { @@ -214,12 +210,7 @@ describe('PaymentMethodActionCreator', () => { expect( paymentMethodRequestSender.loadPaymentWalletWithInitializationData, - ).toHaveBeenCalledWith(methodId, { - headers: { - Authorization: `Bearer storefront_jwt_token`, - 'Content-Type': 'application/json', - }, - }); + ).toHaveBeenCalledWith(methodId, undefined, undefined); }); it('loads payment wallet method with timeout', async () => { @@ -237,13 +228,7 @@ describe('PaymentMethodActionCreator', () => { expect( paymentMethodRequestSender.loadPaymentWalletWithInitializationData, - ).toHaveBeenCalledWith(methodId, { - headers: { - Authorization: `Bearer storefront_jwt_token`, - 'Content-Type': 'application/json', - }, - ...options, - }); + ).toHaveBeenCalledWith(methodId, undefined, options); }); it('emits actions if able to load payment wallet method', async () => { diff --git a/packages/core/src/payment/payment-method-action-creator.ts b/packages/core/src/payment/payment-method-action-creator.ts index 4355c73d7e..40e0eabf3e 100644 --- a/packages/core/src/payment/payment-method-action-creator.ts +++ b/packages/core/src/payment/payment-method-action-creator.ts @@ -4,7 +4,6 @@ import { Observable, Observer } from 'rxjs'; import { InternalCheckoutSelectors } from '../checkout'; import { ActionOptions, cachableAction } from '../common/data-store'; -import { MissingDataError, MissingDataErrorType } from '../common/error/errors'; import { RequestOptions } from '../common/http-request'; import { @@ -169,11 +168,7 @@ export default class PaymentMethodActionCreator { return (store) => Observable.create((observer: Observer) => { const state = store.getState(); - const jwtToken = state.config.getStorefrontJwtToken(); - - if (!jwtToken) { - throw new MissingDataError(MissingDataErrorType.MissingPaymentToken); - } + const host = state.config.getHost(); observer.next( createAction(PaymentMethodActionType.LoadPaymentMethodRequested, undefined, { @@ -182,13 +177,7 @@ export default class PaymentMethodActionCreator { ); this._requestSender - .loadPaymentWalletWithInitializationData(methodId, { - headers: { - Authorization: `Bearer ${jwtToken}`, - 'Content-Type': 'application/json', - }, - ...options, - }) + .loadPaymentWalletWithInitializationData(methodId, host, options) .then((response) => { observer.next( createAction( diff --git a/packages/core/src/payment/payment-method-request-sender.spec.ts b/packages/core/src/payment/payment-method-request-sender.spec.ts index 29740457b1..d8f0bbd686 100644 --- a/packages/core/src/payment/payment-method-request-sender.spec.ts +++ b/packages/core/src/payment/payment-method-request-sender.spec.ts @@ -141,7 +141,6 @@ describe('PaymentMethodRequestSender', () => { describe('#loadPaymentWalletWithInitializationData()', () => { let response: Response; - const authorization = 'authorization-1234'; beforeEach(() => { response = getHeadlessPaymentResponse(getHeadlessPaymentMethod()); @@ -149,18 +148,20 @@ describe('PaymentMethodRequestSender', () => { }); it('loads headless payment method', async () => { + const host = 'https://test.com'; + const path = 'get-initialization-data'; + const walletInitData = await paymentMethodRequestSender.loadPaymentWalletWithInitializationData( 'paypalcommerce', - { headers: { Authorization: authorization } }, + host, ); expect(requestSender.post).toHaveBeenCalledWith( - '/graphql', + `${host}/${path}`, expect.objectContaining({ - headers: { - Authorization: authorization, - 'Content-Type': 'application/json', + body: { + entityId: 'paypalcommerce.paypal', }, }), ); diff --git a/packages/core/src/payment/payment-method-request-sender.ts b/packages/core/src/payment/payment-method-request-sender.ts index df5eb921bf..d8df3537fa 100644 --- a/packages/core/src/payment/payment-method-request-sender.ts +++ b/packages/core/src/payment/payment-method-request-sender.ts @@ -11,8 +11,8 @@ import { HeadlessPaymentMethodConfig, HeadlessPaymentMethodResponse, HeadlessPaymentMethodType, - HeadlessPaymentRequestOptions, } from './headless-payment'; +import HeadlessPaymentRequestOptions from './headless-payment/headless-payment-request-options'; import PaymentMethod from './payment-method'; import paymentMethodTransformer from './payment-method-transformer'; @@ -53,37 +53,25 @@ export default class PaymentMethodRequestSender { } /** - * GraphQL payment requests + * Headless payment requests */ loadPaymentWalletWithInitializationData( methodId: string, - options: HeadlessPaymentRequestOptions, + host?: string, + { timeout }: RequestOptions = {}, ): Promise> { - const entityId = this._getPaymentEntityId(methodId); - - const graphQLQuery = ` - query { - site { - paymentWalletWithInitializationData(filter: { paymentWalletEntityId: "${entityId}" }) { - clientToken - initializationData - } - } - } - `; + const path = 'get-initialization-data'; + const url = host ? `${host}/${path}` : `/${path}`; const requestOptions: HeadlessPaymentRequestOptions = { - headers: { - ...options.headers, - 'Content-Type': 'application/json', - }, body: { - query: graphQLQuery, + entityId: this._getPaymentEntityId(methodId), }, + timeout, }; return this._requestSender - .post('/graphql', requestOptions) + .post(url, requestOptions) .then((response) => paymentMethodTransformer(response, methodId)); } diff --git a/packages/payment-integration-api/src/payment-integration-selectors.ts b/packages/payment-integration-api/src/payment-integration-selectors.ts index 5f6564f08a..a75d417cdc 100644 --- a/packages/payment-integration-api/src/payment-integration-selectors.ts +++ b/packages/payment-integration-api/src/payment-integration-selectors.ts @@ -85,8 +85,6 @@ export default interface PaymentIntegrationSelectors { getInstrumentsMeta(): InstrumentMeta | undefined; - getStorefrontJwtToken(): string | undefined; - getOrderMeta(): OrderMetaState | undefined; getPaymentMethodsMeta(): PaymentMethodMeta | undefined; diff --git a/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts b/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts index c7deac7aed..5bd6cad0fe 100644 --- a/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts +++ b/packages/payment-integrations-test-utils/src/test-utils/payment-integration-service.mock.ts @@ -59,7 +59,6 @@ const state = { getPaymentRedirectUrl: jest.fn(), getPaymentRedirectUrlOrThrow: jest.fn(), isPaymentDataRequired: jest.fn(), - getStorefrontJwtToken: jest.fn(), }; const createBuyNowCart = jest.fn(() => Promise.resolve(getCart()));