Skip to content

Commit

Permalink
Remove embedded experience
Browse files Browse the repository at this point in the history
Close popup on endExperience
  • Loading branch information
zack-winchell-cb committed May 7, 2024
1 parent 10d331a commit e419197
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 147 deletions.
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ const options = {
},
closeOnExit: true,
closeOnSuccess: true,
embeddedContentStyles: {
target: '#target-area',
},
onExit: () => {
alert('On Exit');
},
Expand Down
2 changes: 1 addition & 1 deletion src/onramp/initOnRamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type InitOnRampCallback = {

export const initOnRamp = (
{
experienceLoggedIn = 'embedded', // default experience type
experienceLoggedIn = 'popup', // default experience type
widgetParameters,
...options
}: InitOnRampParams,
Expand Down
11 changes: 1 addition & 10 deletions src/types/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ export type WidgetType = 'buy' | 'checkout';

export type IntegrationType = 'direct' | 'secure_standalone';

export type Experience = 'embedded' | 'popup' | 'new_tab';
export type Experience = 'popup' | 'new_tab';

export type Theme = 'light' | 'dark';

export type EmbeddedContentStyles = {
target?: string;
width?: string;
height?: string;
position?: string;
top?: string;
};

export type CBPayExperienceOptions<T> = {
widgetParameters: T;
target?: string;
Expand All @@ -29,7 +21,6 @@ export type CBPayExperienceOptions<T> = {
onRequestedUrl?: (url: string) => void;
closeOnExit?: boolean;
closeOnSuccess?: boolean;
embeddedContentStyles?: EmbeddedContentStyles;
experienceLoggedIn?: Experience;
experienceLoggedOut?: Experience;
};
2 changes: 0 additions & 2 deletions src/utils/CBPayInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export class CBPayInstance implements CBPayInstanceType {
widget,
experienceLoggedIn,
experienceLoggedOut,
embeddedContentStyles,
onExit,
onSuccess,
onEvent,
Expand All @@ -65,7 +64,6 @@ export class CBPayInstance implements CBPayInstanceType {
path: widgetRoutes[widget],
experienceLoggedIn,
experienceLoggedOut,
embeddedContentStyles,
onExit: () => {
onExit?.();
if (closeOnExit) {
Expand Down
41 changes: 13 additions & 28 deletions src/utils/CoinbasePixel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
PIXEL_ID,
CoinbasePixelConstructorParams,
OpenExperienceOptions,
popupWindowFeatures,
} from './CoinbasePixel';
import { EMBEDDED_IFRAME_ID } from './createEmbeddedContent';

import { broadcastPostMessage, onBroadcastedPostMessage } from './postMessage';

Expand All @@ -25,13 +25,14 @@ describe('CoinbasePixel', () => {
};
const defaultOpenOptions: OpenExperienceOptions = {
path: '/buy',
experienceLoggedIn: 'embedded',
experienceLoggedIn: 'popup',
};

beforeEach(() => {
mockOnReady = jest.fn();
mockOnFallbackOpen = jest.fn();
mockUnsubCallback = jest.fn();
(window.open as jest.Mock).mockReset();
(onBroadcastedPostMessage as jest.Mock).mockReturnValue(mockUnsubCallback);
defaultArgs = {
appId: 'test',
Expand All @@ -43,7 +44,6 @@ describe('CoinbasePixel', () => {

afterEach(() => {
document.getElementById(PIXEL_ID)?.remove();
document.getElementById(EMBEDDED_IFRAME_ID)?.remove();
// @ts-expect-error - test
window.chrome = undefined;
jest.resetAllMocks();
Expand Down Expand Up @@ -154,7 +154,11 @@ describe('CoinbasePixel', () => {

pixel.openExperience(defaultOpenOptions);

expect(document.querySelector(`iframe#${EMBEDDED_IFRAME_ID}`)).toBeTruthy();
expect(window.open).toHaveBeenCalledWith(
'https://pay.coinbase.com/buy?appId=test&type=secure_standalone&nonce=mock-nonce',
'Coinbase',
popupWindowFeatures,
);
});

it('should handle openExperience when pixel has status "loading"', () => {
Expand All @@ -163,7 +167,7 @@ describe('CoinbasePixel', () => {
expect(instance.state).toEqual('loading');
instance.openExperience(defaultOpenOptions);

expect(document.querySelector(`iframe#${EMBEDDED_IFRAME_ID}`)).toBeFalsy();
expect(window.open).not.toHaveBeenCalled();
});

it('should handle openExperience when pixel has status "waiting_for_response"', () => {
Expand All @@ -173,7 +177,7 @@ describe('CoinbasePixel', () => {
instance.openExperience(defaultOpenOptions);

expect(instance.queuedOpenOptions).toBeFalsy();
expect(document.querySelector(`iframe#${EMBEDDED_IFRAME_ID}`)).toBeFalsy();
expect(window.open).not.toHaveBeenCalled();
});

it('should handle openExperience when pixel has status "failed"', () => {
Expand All @@ -183,7 +187,7 @@ describe('CoinbasePixel', () => {
instance.openExperience(defaultOpenOptions);

expect(instance.queuedOpenOptions).toBeFalsy();
expect(document.querySelector(`iframe#${EMBEDDED_IFRAME_ID}`)).toBeFalsy();
expect(window.open).not.toHaveBeenCalled();
});

it('should handle openExperience with no preloaded nonce', () => {
Expand All @@ -195,22 +199,7 @@ describe('CoinbasePixel', () => {
'Attempted to open CB Pay experience without nonce',
);

expect(document.querySelector(`iframe#${EMBEDDED_IFRAME_ID}`)).toBeFalsy();
});

it('should handle opening the embedded experience when logged out', () => {
const instance = createUntypedPixel(defaultArgs);

mockPixelReady(false);
mockOnAppParamsNonce('mock-nonce');
instance.openExperience(defaultOpenOptions);

expect(window.open).toHaveBeenCalledWith(
'https://pay.coinbase.com/signin?appId=test&type=direct',
'Coinbase',
'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, height=730,width=460',
);
expect(findMockedListeners('signin_success')).toHaveLength(1);
expect(window.open).not.toHaveBeenCalled();
});

it('should handle opening the popup experience in chrome extensions', () => {
Expand Down Expand Up @@ -271,7 +260,7 @@ describe('CoinbasePixel', () => {
expect(window.open).toHaveBeenCalledWith(
'https://pay.coinbase.com/buy?appId=test&type=secure_standalone&nonce=mock-nonce',
'Coinbase',
'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, height=730,width=460',
popupWindowFeatures,
);
});

Expand Down Expand Up @@ -358,7 +347,3 @@ function mockOnAppParamsNonce(nonce: string) {
call[1].onMessage({ nonce });
});
}

function findMockedListeners(message: string) {
return (onBroadcastedPostMessage as jest.Mock).mock.calls.filter(([m]) => m === message);
}
52 changes: 22 additions & 30 deletions src/utils/CoinbasePixel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DEFAULT_HOST } from '../config';
import { EmbeddedContentStyles, Experience, Theme } from 'types/widget';
import { createEmbeddedContent, EMBEDDED_IFRAME_ID } from './createEmbeddedContent';
import { Experience, Theme } from 'types/widget';
import { JsonObject } from 'types/JsonTypes';
import { broadcastPostMessage, onBroadcastedPostMessage } from './postMessage';
import { EventMetadata } from 'types/events';
Expand Down Expand Up @@ -44,9 +43,21 @@ export type OpenExperienceOptions = {
path: string;
experienceLoggedIn: Experience;
experienceLoggedOut?: Experience;
embeddedContentStyles?: EmbeddedContentStyles;
} & ExperienceListeners;

export const popupWindowFeatures = [
'copyhistory=no',
'directories=no',
'location=no',
'menubar=no',
'resizable=no',
'scrollbars=no',
'status=no',
'toolbar=no',
`height=${PopupSizes.signin.height}`,
`width=${PopupSizes.signin.width}`,
].join(', ');

export class CoinbasePixel {
/**
* Tracks the loading state of the embedded pixel
Expand All @@ -71,6 +82,7 @@ export class CoinbasePixel {
private onReadyCallback: CoinbasePixelConstructorParams['onReady'];
private onFallbackOpen: CoinbasePixelConstructorParams['onFallbackOpen'];
private theme: Theme | null | undefined;
private widgetWindow: Window | null;

public isLoggedIn = false;

Expand All @@ -90,6 +102,7 @@ export class CoinbasePixel {
this.onFallbackOpen = onFallbackOpen;
this.debug = debug || false;
this.theme = theme;
this.widgetWindow = null;

this.addPixelReadyListener();
this.addErrorListener();
Expand Down Expand Up @@ -132,7 +145,7 @@ export class CoinbasePixel {

this.setupExperienceListeners(options);

const { path, experienceLoggedIn, experienceLoggedOut, embeddedContentStyles } = options;
const { path, experienceLoggedIn, experienceLoggedOut } = options;

const widgetUrl = new URL(`${this.host}${path}`);
widgetUrl.searchParams.append('appId', this.appId);
Expand All @@ -151,23 +164,7 @@ export class CoinbasePixel {

this.log('Opening experience', { experience, isLoggedIn: this.isLoggedIn });

if (experience === 'embedded') {
const openEmbeddedExperience = () => {
const embedded = createEmbeddedContent({ url, ...embeddedContentStyles });
if (embeddedContentStyles?.target) {
document.querySelector(embeddedContentStyles?.target)?.replaceChildren(embedded);
} else {
document.body.appendChild(embedded);
}
};

if (!this.isLoggedIn) {
// Embedded experience opens popup for signin
this.startDirectSignin(openEmbeddedExperience);
} else {
openEmbeddedExperience();
}
} else if (experience === 'popup' && window.chrome?.windows?.create) {
if (experience === 'popup' && window.chrome?.windows?.create) {
void window.chrome.windows.create(
{
url,
Expand Down Expand Up @@ -195,7 +192,7 @@ export class CoinbasePixel {
} else if (experience === 'new_tab' && window.chrome?.tabs?.create) {
void window.chrome.tabs.create({ url });
} else {
openWindow(url, experience);
this.widgetWindow = openWindow(url, experience);
}

// For users who exit the experience and want to re-enter, we need a fresh nonce to use.
Expand All @@ -209,7 +206,8 @@ export class CoinbasePixel {
};

public endExperience = (): void => {
document.getElementById(EMBEDDED_IFRAME_ID)?.remove();
this.widgetWindow?.close();
this.widgetWindow = null;
};

public destroy = (): void => {
Expand Down Expand Up @@ -394,11 +392,5 @@ function createPixel({ host, appId }: { host: string; appId: string }) {
}

function openWindow(url: string, experience: Experience) {
return window.open(
url,
'Coinbase',
experience === 'popup'
? `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, height=${PopupSizes.signin.height},width=${PopupSizes.signin.width}`
: undefined,
);
return window.open(url, 'Coinbase', experience === 'popup' ? popupWindowFeatures : undefined);
}
46 changes: 0 additions & 46 deletions src/utils/createEmbeddedContent.test.ts

This file was deleted.

27 changes: 0 additions & 27 deletions src/utils/createEmbeddedContent.ts

This file was deleted.

0 comments on commit e419197

Please sign in to comment.