Skip to content

Commit

Permalink
fix(connect): defer token creation after iframe open (#2812)
Browse files Browse the repository at this point in the history
## Describe your changes

- Defer token creation after iframe open
Allow to pass the token after the iframe is created so we can display a
loading screen instead of just nothing
  • Loading branch information
bodinsamuel authored Oct 3, 2024
1 parent 04c07c1 commit 195e526
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
30 changes: 26 additions & 4 deletions packages/frontend/lib/connectUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import type { MaybePromise } from '@nangohq/types';
import type { ConnectUIEvent, ConnectUIEventToken } from './types';

export interface ConnectUIProps {
sessionToken: string;
sessionToken?: string;
baseURL?: string;
onEvent?: (event: ConnectUIEvent) => MaybePromise<void>;
}

export class ConnectUI {
iframe: HTMLIFrameElement | null = null;

private isReady = false;
private listener: ((this: Window, ev: MessageEvent) => any) | null = null;
private sessionToken;
private baseURL;
private onEvent;
iframe: HTMLIFrameElement | null = null;

constructor({ sessionToken, baseURL = 'http://localhost:5173', onEvent }: ConnectUIProps) {
this.sessionToken = sessionToken;
Expand Down Expand Up @@ -59,8 +61,9 @@ export class ConnectUI {

switch (evt.type) {
case 'ready': {
const data: ConnectUIEventToken = { type: 'session_token', sessionToken: this.sessionToken };
this.iframe?.contentWindow?.postMessage(data, '*');
this.isReady = true;
this.sendSessionToken();

break;
}
case 'close': {
Expand All @@ -80,6 +83,16 @@ export class ConnectUI {
window.addEventListener('message', this.listener, false);
}

/**
* Set the session token and send it to the Connect UI iframe
*/
setSessionToken(sessionToken: string) {
this.sessionToken = sessionToken;
if (this.isReady) {
this.sendSessionToken();
}
}

/**
* Close UI and clear state
*/
Expand All @@ -92,4 +105,13 @@ export class ConnectUI {
this.iframe = null;
}
}

private sendSessionToken() {
if (!this.sessionToken) {
return;
}

const data: ConnectUIEventToken = { type: 'session_token', sessionToken: this.sessionToken };
this.iframe?.contentWindow?.postMessage(data, '*');
}
}
18 changes: 11 additions & 7 deletions packages/webapp/src/pages/Connection/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,11 @@ export default function ConnectionList() {
};
}, [debouncedSearch]);

const onClickConnectUI = async () => {
const onClickConnectUI = () => {
if (!environmentAndAccount) {
return;
}

const res = await apiConnectSessions(env);
if ('error' in res.json) {
return;
}

const nango = new Nango({
host: environmentAndAccount.host || baseUrl(),
websocketsPath: environmentAndAccount.environment.websockets_path || '',
Expand All @@ -128,14 +123,23 @@ export default function ConnectionList() {

connectUI.current = nango.openConnectUI({
baseURL: globalEnv.connectUrl,
sessionToken: res.json.data.token,
onEvent: (event) => {
if (event.type === 'close') {
// we refresh on close so user can see the diff
void mutate();
}
}
});

// We defer the token creation so the iframe can open and display a loading screen
// instead of blocking the main loop and no visual clue for the end user
setTimeout(async () => {
const res = await apiConnectSessions(env);
if ('error' in res.json) {
return;
}
connectUI.current!.setSessionToken(res.json.data.token);
}, 10);
};

if (error) {
Expand Down

0 comments on commit 195e526

Please sign in to comment.