From f499af25b619be984488770984acba83ebda0622 Mon Sep 17 00:00:00 2001 From: simbirromanmakarov Date: Thu, 12 Dec 2024 13:37:13 +0400 Subject: [PATCH] feat(PAYMENTS-21797): add form submit action --- README.md | 6 ++++++ .../headless-checkout.spec.ts | 10 +++++++++ .../headless-checkout/headless-checkout.ts | 17 ++++++++++++++- .../submit/submit.handler.spec.ts | 19 +++++++++++++++++ .../submit/submit.handler.ts | 14 +++++++++++++ .../default-submit-button.component.ts | 4 ++-- .../default-submit-button.handler.spec.ts | 21 ------------------- .../default-submit-button.handler.ts | 14 ------------- 8 files changed, 67 insertions(+), 38 deletions(-) create mode 100644 src/features/headless-checkout/post-messages-handlers/submit/submit.handler.spec.ts create mode 100644 src/features/headless-checkout/post-messages-handlers/submit/submit.handler.ts delete mode 100644 src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.spec.ts delete mode 100644 src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.ts diff --git a/README.md b/README.md index 451fe18..34bdaba 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,12 @@ declare const headlessCheckout: { * Allows you to prepare components before a user can interact with them. */ activate(): void; + + /** + * Initiate form submit. + * To get submit action response listen onNextAction events + */ + submit(): void; }; /** diff --git a/src/features/headless-checkout/headless-checkout.spec.ts b/src/features/headless-checkout/headless-checkout.spec.ts index c8f367f..5ae51dc 100644 --- a/src/features/headless-checkout/headless-checkout.spec.ts +++ b/src/features/headless-checkout/headless-checkout.spec.ts @@ -10,6 +10,7 @@ import { FormStatus } from '../../core/status/form-status.enum'; import { noopStub } from '../../tests/stubs/noop.stub'; import { headlessCheckoutAppUrl } from './environment'; import { ThemesLoader } from '../../core/customization/themes-loader'; +import { submitHandler } from './post-messages-handlers/submit/submit.handler'; const mockMessage: Message = { name: EventName.initPayment, @@ -247,4 +248,13 @@ describe('HeadlessCheckout', () => { headlessCheckout.form.onFieldsStatusChange(noopStub); expect(spy).toHaveBeenCalled(); }); + + it('Should init', async () => { + const spy = spyOn(postMessagesClient, 'send'); + await headlessCheckout.form.submit(); + expect(spy).toHaveBeenCalledWith( + { name: EventName.submitForm }, + submitHandler, + ); + }); }); diff --git a/src/features/headless-checkout/headless-checkout.ts b/src/features/headless-checkout/headless-checkout.ts index d402f3e..15a2dd7 100644 --- a/src/features/headless-checkout/headless-checkout.ts +++ b/src/features/headless-checkout/headless-checkout.ts @@ -39,6 +39,7 @@ import { getCountryListHandler } from './post-messages-handlers/get-country-list import { CountryResponse } from '../../core/country-response.interface'; import { FormLoader } from '../../core/form/form-loader'; import { InitialOptions } from './initial-options.interface'; +import { submitHandler } from './post-messages-handlers/submit/submit.handler'; @singleton() export class HeadlessCheckout { @@ -138,8 +139,18 @@ export class HeadlessCheckout { activate: (): void => { this.formStatus = FormStatus.active; }, + setupAndAwaitFieldsLoading: async (fields: Field[]): Promise => this.formLoader.setupAndAwaitFieldsLoading(fields), + + submit: async (): Promise => { + await this.postMessagesClient.send( + { + name: EventName.submitForm, + }, + submitHandler, + ); + }, }; public get formConfiguration(): FormConfiguration | undefined { @@ -411,8 +422,12 @@ export class HeadlessCheckout { private async listenCoreIframeLoading(): Promise { return new Promise((resolve) => { const handler = (event: MessageEvent): void => { + if (typeof event.data !== 'string') { + return; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (JSON.parse(event.data as string).name === EventName.isReady) { + if (JSON.parse(event.data).name === EventName.isReady) { resolve(); this.window.removeEventListener('message', handler); } diff --git a/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.spec.ts b/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.spec.ts new file mode 100644 index 0000000..2a756ef --- /dev/null +++ b/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.spec.ts @@ -0,0 +1,19 @@ +import { EventName } from '../../../../core/event-name.enum'; +import { Message } from '../../../../core/message.interface'; +import { PaymentMethod } from '../../../../core/payment-method.interface'; +import { submitHandler } from './submit.handler'; + +const mockMessage: Message<{ methods: PaymentMethod[] }> = { + name: EventName.submitForm, + data: { methods: [] }, +}; +describe('submitHandler', () => { + it('Should handle data', () => { + expect(submitHandler(mockMessage)).toEqual({ + isHandled: true, + }); + }); + it('Should return null', () => { + expect(submitHandler({ name: EventName.initPayment })).toBeNull(); + }); +}); diff --git a/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.ts b/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.ts new file mode 100644 index 0000000..3868f58 --- /dev/null +++ b/src/features/headless-checkout/post-messages-handlers/submit/submit.handler.ts @@ -0,0 +1,14 @@ +import { Handler } from '../../../../core/post-messages-client/handler.type'; +import { Message } from '../../../../core/message.interface'; +import { EventName } from '../../../../core/event-name.enum'; + +export const submitHandler: Handler = ( + message: Message, +): { isHandled: boolean } | null => { + if (message.name === EventName.submitForm) { + return { + isHandled: true, + }; + } + return null; +}; diff --git a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.component.ts b/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.component.ts index cf0c57d..03d8fb7 100644 --- a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.component.ts +++ b/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.component.ts @@ -5,7 +5,7 @@ import { EventName } from '../../../../../core/event-name.enum'; import { HeadlessCheckout } from '../../../headless-checkout'; import { DefaultSubmitButtonAttributes } from './default-submit-button-attributes.enum'; import { getSubmitButtonTemplate } from './default-submit-button.template'; -import { defaultSubmitButtonHandler } from './default-submit-button.handler'; +import { submitHandler } from '../../../post-messages-handlers/submit/submit.handler'; import { Message } from '../../../../../core/message.interface'; import { Handler } from '../../../../../core/post-messages-client/handler.type'; import { isSubmitButtonLoadingMessage } from '../../../../../core/guards/submit-button-loading-message.guard'; @@ -75,7 +75,7 @@ export class DefaultSubmitButtonComponent extends WebComponentAbstract { void this.postMessagesClient.send( { name: EventName.submitForm }, - defaultSubmitButtonHandler, + submitHandler, ); this.render(); diff --git a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.spec.ts b/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.spec.ts deleted file mode 100644 index 6af4bbf..0000000 --- a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { EventName } from '../../../../../core/event-name.enum'; -import { Message } from '../../../../../core/message.interface'; -import { PaymentMethod } from '../../../../../core/payment-method.interface'; -import { defaultSubmitButtonHandler } from './default-submit-button.handler'; - -const mockMessage: Message<{ methods: PaymentMethod[] }> = { - name: EventName.submitForm, - data: { methods: [] }, -}; -describe('submitButtonHandler', () => { - it('Should handle data', () => { - expect(defaultSubmitButtonHandler(mockMessage)).toEqual({ - isHandled: true, - }); - }); - it('Should return null', () => { - expect( - defaultSubmitButtonHandler({ name: EventName.initPayment }) - ).toBeNull(); - }); -}); diff --git a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.ts b/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.ts deleted file mode 100644 index 620d48d..0000000 --- a/src/features/headless-checkout/web-components/submit-button/default-submit-button/default-submit-button.handler.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Handler } from '../../../../../core/post-messages-client/handler.type'; -import { Message } from '../../../../../core/message.interface'; -import { EventName } from '../../../../../core/event-name.enum'; - -export const defaultSubmitButtonHandler: Handler = ( - message: Message -): { isHandled: boolean } | null => { - if (message.name === EventName.submitForm) { - return { - isHandled: true, - }; - } - return null; -};