Skip to content

Commit b91efd7

Browse files
authored
Merge pull request #2841 from bigcommerce/feat/google-pay-spinner
feat(payment): Added loadingIndicator to the google-pay-payment-strategy
2 parents 6f2312c + 27ca8fd commit b91efd7

File tree

6 files changed

+55
-3
lines changed

6 files changed

+55
-3
lines changed

packages/google-pay-integration/src/google-pay-payment-initialize-options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
* ```
3939
*/
4040
export default interface GooglePayPaymentInitializeOptions {
41+
/**
42+
* A container for loading spinner.
43+
*/
44+
loadingContainerId?: string;
45+
4146
/**
4247
* This walletButton is used to set an event listener, provide an element ID if you want
4348
* users to be able to launch the GooglePay wallet modal by clicking on a button.

packages/google-pay-integration/src/google-pay-payment-strategy.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ import {
3636
NewTransactionInfo,
3737
} from './types';
3838

39+
const LoadingShow = jest.fn();
40+
const LoadingHide = jest.fn();
41+
42+
jest.mock('@bigcommerce/checkout-sdk/ui', () => ({
43+
LoadingIndicator: jest.fn().mockImplementation(() => ({
44+
show: LoadingShow,
45+
hide: LoadingHide,
46+
})),
47+
}));
48+
3949
describe('GooglePayPaymentStrategy', () => {
4050
const BUTTON_ID = 'my_awesome_google_pay_button';
4151

@@ -99,6 +109,7 @@ describe('GooglePayPaymentStrategy', () => {
99109
options = {
100110
methodId: 'googlepayworldpayaccess',
101111
googlepayworldpayaccess: {
112+
loadingContainerId: 'id',
102113
walletButton: BUTTON_ID,
103114
onError: jest.fn(),
104115
onPaymentSelect: jest.fn(),
@@ -333,6 +344,7 @@ describe('GooglePayPaymentStrategy', () => {
333344

334345
await new Promise((resolve) => process.nextTick(resolve));
335346

347+
expect(LoadingHide).toHaveBeenCalled();
336348
expect(rejectedInitializeWidgetMock).toHaveBeenCalledTimes(1);
337349
expect(options.googlepayworldpayaccess?.onError).toHaveBeenCalled();
338350
});
@@ -371,6 +383,7 @@ describe('GooglePayPaymentStrategy', () => {
371383

372384
expect(paymentIntegrationService.loadCheckout).toHaveBeenCalled();
373385
expect(initializeWidgetMock).toHaveBeenCalledTimes(1);
386+
expect(LoadingShow).toHaveBeenCalled();
374387
});
375388

376389
it('should return updated transactionInfo', async () => {

packages/google-pay-integration/src/google-pay-payment-strategy.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
PaymentMethodFailedError,
1717
PaymentStrategy,
1818
} from '@bigcommerce/checkout-sdk/payment-integration-api';
19+
import { DEFAULT_CONTAINER_STYLES, LoadingIndicator } from '@bigcommerce/checkout-sdk/ui';
1920

2021
import GooglePayPaymentInitializeOptions, {
2122
WithGooglePayPaymentInitializeOptions,
@@ -35,14 +36,20 @@ import {
3536
} from './types';
3637

3738
export default class GooglePayPaymentStrategy implements PaymentStrategy {
39+
private _loadingIndicator: LoadingIndicator;
40+
private _loadingIndicatorContainer?: string;
3841
private _paymentButton?: HTMLElement;
3942
private _clickListener?: (event: MouseEvent) => unknown;
4043
private _methodId?: keyof WithGooglePayPaymentInitializeOptions;
4144

4245
constructor(
4346
protected _paymentIntegrationService: PaymentIntegrationService,
4447
protected _googlePayPaymentProcessor: GooglePayPaymentProcessor,
45-
) {}
48+
) {
49+
this._loadingIndicator = new LoadingIndicator({
50+
containerStyles: DEFAULT_CONTAINER_STYLES,
51+
});
52+
}
4653

4754
async initialize(
4855
options?: PaymentInitializeOptions & WithGooglePayPaymentInitializeOptions,
@@ -61,7 +68,9 @@ export default class GooglePayPaymentStrategy implements PaymentStrategy {
6168
throw new InvalidArgumentError('Unable to proceed without valid options.');
6269
}
6370

64-
const { walletButton, ...callbacks } = googlePayOptions;
71+
const { walletButton, loadingContainerId, ...callbacks } = googlePayOptions;
72+
73+
this._loadingIndicatorContainer = loadingContainerId;
6574

6675
await this._paymentIntegrationService.loadPaymentMethod(this._getMethodId());
6776

@@ -147,6 +156,8 @@ export default class GooglePayPaymentStrategy implements PaymentStrategy {
147156
} catch (error) {
148157
let err: unknown = error;
149158

159+
this._toggleLoadingIndicator(false);
160+
150161
if (isGooglePayErrorObject(error)) {
151162
if (error.statusCode === 'CANCELED') {
152163
throw new PaymentMethodCancelledError();
@@ -170,6 +181,9 @@ export default class GooglePayPaymentStrategy implements PaymentStrategy {
170181

171182
protected async _interactWithPaymentSheet(): Promise<void> {
172183
const response = await this._googlePayPaymentProcessor.showPaymentSheet();
184+
185+
this._toggleLoadingIndicator(true);
186+
173187
const billingAddress =
174188
this._googlePayPaymentProcessor.mapToBillingAddressRequestBody(response);
175189

@@ -181,6 +195,7 @@ export default class GooglePayPaymentStrategy implements PaymentStrategy {
181195

182196
await this._paymentIntegrationService.loadCheckout();
183197
await this._paymentIntegrationService.loadPaymentMethod(this._getMethodId());
198+
this._toggleLoadingIndicator(false);
184199
}
185200

186201
protected _getMethodId(): keyof WithGooglePayPaymentInitializeOptions {
@@ -298,4 +313,12 @@ export default class GooglePayPaymentStrategy implements PaymentStrategy {
298313
},
299314
};
300315
}
316+
317+
private _toggleLoadingIndicator(isLoading: boolean): void {
318+
if (isLoading && this._loadingIndicatorContainer) {
319+
this._loadingIndicator.show(this._loadingIndicatorContainer);
320+
} else {
321+
this._loadingIndicator.hide();
322+
}
323+
}
301324
}

packages/ui/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
export { Overlay } from './overlay';
2-
export { LoadingIndicator, LoadingIndicatorStyles } from './loading-indicator';
2+
export {
3+
LoadingIndicator,
4+
LoadingIndicatorStyles,
5+
DEFAULT_CONTAINER_STYLES,
6+
} from './loading-indicator';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as LoadingIndicator } from './loading-indicator';
2+
export { DEFAULT_CONTAINER_STYLES } from './loading-indicator';
23
export { LoadingIndicatorStyles } from './loading-indicator-styles';

packages/ui/src/loading-indicator/loading-indicator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ const DEFAULT_STYLES: LoadingIndicatorStyles = {
99
backgroundColor: '#ffffff',
1010
};
1111

12+
export const DEFAULT_CONTAINER_STYLES = {
13+
position: 'fixed',
14+
'background-color': 'rgba(0, 0, 0, 0.4)',
15+
'z-index': '1000',
16+
};
17+
1218
const ROTATION_ANIMATION = 'embedded-checkout-loading-indicator-rotation';
1319

1420
interface LoadingIndicatorOptions {

0 commit comments

Comments
 (0)