Skip to content

Commit

Permalink
feat(PAYMENTS-18631): add country selector
Browse files Browse the repository at this point in the history
  • Loading branch information
ekireevxs committed Mar 29, 2024
1 parent edff94c commit 6978926
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 41 deletions.
5 changes: 5 additions & 0 deletions src/core/country-response.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Country } from './country.interface';

export interface CountryResponse {
countryList: Country[];
}
5 changes: 5 additions & 0 deletions src/core/country.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Country {
ISO: string;
aliases: null | string;
name: string;
}
2 changes: 2 additions & 0 deletions src/core/event-name.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const enum EventName {
initPayment = 'initPayment',
initForm = 'initForm',
submitForm = 'submitForm',
getCountryList = 'getCountryList',
getPaymentMethodsList = 'getPaymentMethodsList',
getPaymentQuickMethods = 'getPaymentQuickMethods',
getCombinedPaymentMethods = 'getCombinedPaymentMethods',
Expand Down Expand Up @@ -32,4 +33,5 @@ export const enum EventName {
applePayError = 'applePayError',
openApplePayPage = 'openApplePayPage',
submitApplePayForm = 'submitApplePayForm',
userCountryChanged = 'userCountryChanged',
}
20 changes: 20 additions & 0 deletions src/core/guards/country-list-event-message.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Message } from '../../core/message.interface';
import { isEventMessage } from './event-message.guard';
import { EventName } from '../../core/event-name.enum';
import { CountryResponse } from '../country-response.interface';

export const isCountryListEventMessage = (
messageData: unknown,
): messageData is Message<{
countryList: CountryResponse['countryList'];
currentCountry: string;
}> => {
if (isEventMessage(messageData)) {
return (
messageData.name === EventName.getCountryList &&
(messageData.data as { [key: string]: unknown })?.countryList !==
undefined
);
}
return false;
};
19 changes: 19 additions & 0 deletions src/features/headless-checkout/headless-checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import { CombinedPaymentMethods } from '../../core/combined-payment-methods.inte
import { themes } from '../../core/customization/themes.map';
import { ThemesLoader } from '../../core/customization/themes-loader';
import { Lang } from '../../core/i18n/lang.enum';
import { getCountryListHandler } from './post-messages-handlers/get-country-list.handler';
import { CountryResponse } from '../../core/country-response.interface';

@singleton()
export class HeadlessCheckout {
Expand Down Expand Up @@ -331,6 +333,23 @@ export class HeadlessCheckout {
return this.localizeService.getAvailableLanguages();
}

public async getCountryList(): Promise<{
countryList: CountryResponse['countryList'];
currentCountry: string;
}> {
const msg: Message = {
name: EventName.getCountryList,
};

return this.postMessagesClient.send<{
countryList: CountryResponse['countryList'];
currentCountry: string;
}>(msg, getCountryListHandler) as Promise<{
countryList: CountryResponse['countryList'];
currentCountry: string;
}>;
}

private async setupCoreIframe(): Promise<void> {
this.coreIframe = this.window.document.createElement('iframe');
this.coreIframe.width = '0px';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Handler } from '../../../core/post-messages-client/handler.type';
import { Message } from '../../../core/message.interface';
import { CountryResponse } from '../../../core/country-response.interface';
import { isCountryListEventMessage } from '../../../core/guards/country-list-event-message.guard';

export const getCountryListHandler: Handler<{
countryList: CountryResponse['countryList'];
currentCountry: string;
}> = (
message: Message,
): {
isHandled: boolean;
value: {
countryList: CountryResponse['countryList'];
currentCountry: string;
};
} | null => {
if (!isCountryListEventMessage(message)) {
return null;
}

const countryList = message.data?.countryList ?? [];
const currentCountry = message.data?.currentCountry ?? '';

return {
isHandled: true,
value: { countryList, currentCountry },
};
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export enum SelectAttributes {
name = 'name',
type = 'type',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum SelectType {
country = 'country',
formControl = 'form-control',
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { WebComponentTagName } from '../../../../core/web-components/web-compone
import { HeadlessCheckout } from '../../headless-checkout';
import { SelectAttributes } from './select-attributes.enum';
import { SelectComponent } from './select.component';
import { HeadlessCheckoutSpy } from '../../../../core/spy/headless-checkout-spy/headless-checkout-spy';

function createComponent(name: string): HTMLElement {
const element = document.createElement(WebComponentTagName.SelectComponent);
Expand Down Expand Up @@ -34,6 +35,7 @@ const configMock = {
describe('SelectComponent', () => {
let postMessagesClient: PostMessagesClient;
let headlessCheckout: HeadlessCheckout;
let headlessCheckoutSpy: HeadlessCheckoutSpy;

window.customElements.define(
WebComponentTagName.SelectComponent,
Expand All @@ -53,6 +55,13 @@ describe('SelectComponent', () => {
},
} as unknown as HeadlessCheckout;

headlessCheckoutSpy = {
listenAppInit: noopStub,
get appWasInit() {
return true;
},
} as unknown as HeadlessCheckoutSpy;

container.clearInstances();

container
Expand All @@ -64,11 +73,24 @@ describe('SelectComponent', () => {
})
.register(Window, {
useValue: window,
})
.register(HeadlessCheckoutSpy, {
useValue: headlessCheckoutSpy,
});
});

afterEach(() => {
document.body.innerHTML = '';
const appWasInitSpy = spyOnProperty(
headlessCheckoutSpy,
'appWasInit',
'get',
);
const listenAppInitSpy = spyOn(headlessCheckoutSpy, 'listenAppInit');
listenAppInitSpy.and.callFake((callback: () => void) => {
appWasInitSpy.and.returnValue(true);
callback();
});
});

it('Should create component', () => {
Expand Down
Loading

0 comments on commit 6978926

Please sign in to comment.