Skip to content

Commit

Permalink
[PAYMENTS-15240] text input
Browse files Browse the repository at this point in the history
  • Loading branch information
ekireevxs committed Jul 31, 2023
1 parent a0d0528 commit 7e0b6f2
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 37 deletions.
49 changes: 49 additions & 0 deletions src/core/spy/form-spy/form-spy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'reflect-metadata';
import { container } from 'tsyringe';
import { FormSpy } from './form-spy';

class Observer {
public formInitHandler(): void {
return;
}
}

describe('FormSpy', () => {
let formSpy: FormSpy;

beforeEach(() => {
container.clearInstances();
formSpy = container.createChildContainer().resolve(FormSpy);
});

it('Should return true for init form', () => {
formSpy.formWasInit = true;
expect(formSpy.formWasInit).toBeTrue();
});

it('Should call formWasInitHandler', () => {
const observer = new Observer();
const spy = spyOn(observer, 'formInitHandler');
formSpy.listenFormInit(observer.formInitHandler);
formSpy.formWasInit = true;
expect(spy).toHaveBeenCalled();
});

it('Should call formWasInitHandler once', () => {
const observer = new Observer();
const spy = spyOn(observer, 'formInitHandler');
formSpy.listenFormInit(observer.formInitHandler);
formSpy.formWasInit = true;
formSpy.formWasInit = true;
expect(spy).toHaveBeenCalledTimes(1);
});

it('Should call appWasInitHandler once', () => {
const observer = new Observer();
const spy = spyOn(observer, 'formInitHandler');
formSpy.listenFormInit(observer.formInitHandler);
formSpy.formWasInit = true;
formSpy.formWasInit = false;
expect(spy).toHaveBeenCalledTimes(1);
});
});
29 changes: 29 additions & 0 deletions src/core/spy/form-spy/form-spy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { singleton } from 'tsyringe';

@singleton()
export class FormSpy {
private _formWasInit = false;
private readonly _callbacks: Array<() => void> = [];

public set formWasInit(value: boolean) {
if (this._formWasInit === value) {
return;
}
this._formWasInit = value;
if (value) {
this.formWasInitHandler();
}
}

public get formWasInit(): boolean {
return this._formWasInit;
}

public listenFormInit(callback: () => void): void {
this._callbacks.push(callback);
}

private formWasInitHandler(): void {
this._callbacks.forEach((callback) => callback());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { WebComponentAbstract } from '../web-component.abstract';
import { headlessCheckoutAppUrl } from '../../../features/headless-checkout/environment';

export abstract class SecureComponentAbstract extends WebComponentAbstract {
protected abstract componentName: string;
protected componentName: string | null = null;

protected getSecureHtml(): string {
if (!this.componentName) {
throw new Error('Component name is required');
}

return `<iframe src='${headlessCheckoutAppUrl}/secure-components/${this.componentName}'></iframe>`;
}
}
2 changes: 1 addition & 1 deletion src/core/web-components/web-component-tag-name.enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export enum WebComponentTagName {
CardNumberComponent = 'psdk-card-number',
TextComponent = 'psdk-text-component',
SubmitButtonComponent = 'psdk-submit-button',
PaymentMethodsComponent = 'psdk-payment-methods',
LegalComponent = 'psdk-legal',
Expand Down
4 changes: 2 additions & 2 deletions src/core/web-components/web-components.map.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CardNumberComponent } from '../../features/headless-checkout/web-components/card-number/card-number.component';
import { TextComponent } from '../../features/headless-checkout/web-components/text-component/text.component';
import { SubmitButtonComponent } from '../../features/headless-checkout/web-components/submit-button/submit-button.component';
import { WebComponentTagName } from './web-component-tag-name.enum';
import { PaymentMethodsComponent } from '../../features/headless-checkout/web-components/payment-methods/payment-methods.component';
Expand All @@ -7,7 +7,7 @@ import { LegalComponent } from '../../features/headless-checkout/web-components/
export const webComponents: {
[key in WebComponentTagName]: CustomElementConstructor;
} = {
[WebComponentTagName.CardNumberComponent]: CardNumberComponent,
[WebComponentTagName.TextComponent]: TextComponent,
[WebComponentTagName.SubmitButtonComponent]: SubmitButtonComponent,
[WebComponentTagName.PaymentMethodsComponent]: PaymentMethodsComponent,
[WebComponentTagName.LegalComponent]: LegalComponent,
Expand Down
12 changes: 7 additions & 5 deletions src/features/headless-checkout/headless-checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import { SavedMethod } from '../../core/saved-method.interface';
import { getSavedMethodsHandler } from './post-messages-handlers/get-saved-methods.handler';
import { UserBalance } from '../../core/user-balance.interface';
import { getUserBalanceHandler } from './post-messages-handlers/get-user-balance.handler';
import { HeadlessCheckoutSpy } from '../../core/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckoutSpy } from '../../core/spy/headless-checkout-spy/headless-checkout-spy';
import { getRegularMethodsHandler } from './post-messages-handlers/get-regular-methods.handler';
import { FormConfiguration } from '../../core/form/form-configuration.interface';
import { initFormHandler } from './post-messages-handlers/init-form.handler';
import { Form } from '../../core/form/form.interface';
import { NextAction } from '../../core/actions/next-action.interface';
import { nextActionHandler } from './post-messages-handlers/next-action.handler';
import { FormSpy } from '../../core/spy/form-spy/form-spy';

@singleton()
export class HeadlessCheckout {
Expand Down Expand Up @@ -65,9 +66,8 @@ export class HeadlessCheckout {
},
};

return this.postMessagesClient.send<Form>(
msg,
initFormHandler
return this.postMessagesClient.send<Form>(msg, (message) =>
initFormHandler(message, () => (this.formSpy.formWasInit = true))
) as Promise<Form>;
},

Expand All @@ -93,7 +93,8 @@ export class HeadlessCheckout {
private readonly window: Window,
private readonly postMessagesClient: PostMessagesClient,
private readonly localizeService: LocalizeService,
private readonly headlessCheckoutSpy: HeadlessCheckoutSpy
private readonly headlessCheckoutSpy: HeadlessCheckoutSpy,
private readonly formSpy: FormSpy
) {}

public async init(environment: { isWebview: boolean }): Promise<void> {
Expand Down Expand Up @@ -210,6 +211,7 @@ export class HeadlessCheckout {
this.coreIframe.style.border = 'none';
this.coreIframe.style.position = 'absolute';
this.coreIframe.src = `${this.headlessAppUrl}/core`;
this.coreIframe.name = 'core';
this.window.document.body.appendChild(this.coreIframe);
return new Promise((resolve) => {
this.coreIframe.onload = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import { Message } from '../../../core/message.interface';
import { Handler } from '../../../core/post-messages-client/handler.type';

export const initFormHandler: Handler<Form> = (
message: Message
message: Message,
callback?: () => void
): { isHandled: boolean; value?: Form } | null => {
if (isInitFormEventMessage(message)) {
if (typeof callback === 'function') {
callback();
}
return {
isHandled: true,
value: message.data,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { container } from 'tsyringe';
import { WebComponentTagName } from '../../../../core/web-components/web-component-tag-name.enum';
import { HeadlessCheckoutSpy } from '../../../../core/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckoutSpy } from '../../../../core/spy/headless-checkout-spy/headless-checkout-spy';
import { noopStub } from '../../../../tests/stubs/noop.stub';
import { HeadlessCheckout } from '../../headless-checkout';
import { LegalComponent } from './legal.component';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { EventName } from '../../../../core/event-name.enum';
import { HeadlessCheckout } from '../../headless-checkout';
import { getLegalComponentTemplate } from './legal.component.tempate';
import { Message } from '../../../../core/message.interface';
import { HeadlessCheckoutSpy } from '../../../../core/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckoutSpy } from '../../../../core/spy/headless-checkout-spy/headless-checkout-spy';
import { getLegalComponentConfigHandler } from '../../post-messages-handlers/get-legal-component-config.handler';
import { LegalComponentConfig } from './legal-component.config.interface';
import { isEventMessage } from '../../../../core/guards/event-message.guard';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { container } from 'tsyringe';
import { WebComponentTagName } from '../../../../core/web-components/web-component-tag-name.enum';
import { HeadlessCheckoutSpy } from '../../../../core/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckoutSpy } from '../../../../core/spy/headless-checkout-spy/headless-checkout-spy';
import { PaymentMethodsComponent } from './payment-methods.component';
import { noopStub } from '../../../../tests/stubs/noop.stub';
import { PaymentMethodsAttributes } from './payment-methods-attributes.enum';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getPaymentMethodTemplate } from './payment-method.template';
import { filterPaymentMethods } from './filter-payment-methods.function';
import { PaymentMethodsAttributes } from './payment-methods-attributes.enum';
import { PaymentMethodsEvents } from './payment-methods-events.enum';
import { HeadlessCheckoutSpy } from '../../../../core/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckoutSpy } from '../../../../core/spy/headless-checkout-spy/headless-checkout-spy';
import { HeadlessCheckout } from '../../headless-checkout';

export class PaymentMethodsComponent extends WebComponentAbstract {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum TextComponentAttributes {
name = 'name',
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { WebComponentTagName } from '../../../../core/web-components/web-component-tag-name.enum';
import { CardNumberComponent } from './card-number.component';
import { TextComponent } from './text.component';

function createComponent(): void {
const element = document.createElement(
WebComponentTagName.CardNumberComponent
);
const element = document.createElement(WebComponentTagName.TextComponent);
element.setAttribute('name', 'zip');
element.setAttribute('id', 'test');
(document.getElementById('container')! as HTMLElement).appendChild(element);
}

describe('HeadlessCheckout', () => {
window.customElements.define(
WebComponentTagName.CardNumberComponent,
CardNumberComponent
WebComponentTagName.TextComponent,
TextComponent
);

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { SecureComponentAbstract } from '../../../../core/web-components/secure-component/secure-component.abstract';
import { TextComponentAttributes } from './text-component-attributes.enum';
import { container } from 'tsyringe';
import { FormSpy } from '../../../../core/spy/form-spy/form-spy';

export class TextComponent extends SecureComponentAbstract {
private readonly formSpy: FormSpy;
public constructor() {
super();
this.formSpy = container.resolve(FormSpy);
}

public static get observedAttributes(): string[] {
return [TextComponentAttributes.name];
}

protected connectedCallback(): void {
if (!this.formSpy.formWasInit) {
this.formSpy.listenFormInit(() => this.connectedCallback());
return;
}

const inputName = this.getAttribute(TextComponentAttributes.name);
if (!inputName) {
return;
}

this.componentName = `text-input/${inputName}`;
super.render();
}

protected attributeChangedCallback(): void {
this.connectedCallback();
}

protected getHtml(): string {
return `
${this.getSecureHtml()}
`;
}
}
4 changes: 2 additions & 2 deletions src/web-components.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { SubmitButtonComponent } from './features/headless-checkout/web-components/submit-button/submit-button.component';
import { CardNumberComponent } from './features/headless-checkout/web-components/card-number/card-number.component';
import { TextComponent } from './features/headless-checkout/web-components/text-component/text.component';
import { PaymentMethodsComponent } from './features/headless-checkout/web-components/payment-methods/payment-methods.component';
import { LegalComponent } from './features/headless-checkout/web-components/legal/legal.component';

export {
SubmitButtonComponent,
CardNumberComponent,
TextComponent,
PaymentMethodsComponent,
LegalComponent,
};

0 comments on commit 7e0b6f2

Please sign in to comment.