From 67deb6be6be657dbabb5241b1511e9c87612f1d3 Mon Sep 17 00:00:00 2001 From: LukassF Date: Thu, 15 Feb 2024 13:13:36 +0100 Subject: [PATCH 01/13] add: polkadot selector lazy loading without session id --- .../nightly-mobile-main.ts | 31 +++++++---- .../nightly-wallet-selector-page.ts | 8 +-- sdk/packages/selector-base/src/modal.ts | 11 +++- sdk/packages/selector-polkadot/src/adapter.ts | 53 ++++++++++++------- 4 files changed, 70 insertions(+), 33 deletions(-) diff --git a/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts b/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts index 3035309a..72f5edb2 100644 --- a/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts +++ b/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts @@ -1,6 +1,6 @@ import { customElement, property, state } from 'lit/decorators.js' import { tailwindElement } from '../../shared/tailwind.element' -import { LitElement, html } from 'lit' +import { LitElement, PropertyValueMap, html } from 'lit' import { walletsSort } from '../../utils/utils' import style from './nightly-mobile-main.css' import { WalletSelectorItem } from '../../utils/types' @@ -20,18 +20,19 @@ export class NightlyMobileMain extends LitElement { // eslint-disable-next-line @typescript-eslint/no-empty-function openQrPage: () => void = () => {} - private _selectorItems: WalletSelectorItem[] = [] + // private _selectorItems: WalletSelectorItem[] = [] @property({ type: Array }) - get selectorItems(): WalletSelectorItem[] { - return this._selectorItems - } + selectorItems: WalletSelectorItem[] = [] + // get selectorItems(): WalletSelectorItem[] { + // return this._selectorItems + // } - set selectorItems(value: WalletSelectorItem[]) { - this._selectorItems = [...value].sort(walletsSort) + // set selectorItems(value: WalletSelectorItem[]) { + // this._selectorItems = [...value].sort(walletsSort) - this.setItemsCount() - } + // this.setItemsCount() + // } @state() numberOfItems = 2 @@ -60,6 +61,18 @@ export class NightlyMobileMain extends LitElement { this.smallestMobileQuery.addEventListener('change', this.setItemsCount) } + protected updated(_changedProperties: PropertyValueMap | Map): void { + const prevSelectorItems: WalletSelectorItem[] = _changedProperties.get('selectorItems') + + if ( + prevSelectorItems && + !this.selectorItems.filter( + (item) => !prevSelectorItems.find((wallet) => wallet.name === item.name) + ).length + ) + this.selectorItems = [...this.selectorItems].sort(walletsSort) + } + render() { return html`
diff --git a/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts b/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts index ce64a2e8..a0225e9d 100644 --- a/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts +++ b/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts @@ -46,9 +46,11 @@ export class NightlyWalletSelectorPage extends LitElement { const searchText = searchInput.value.toLowerCase() this.searchText = searchText - this.filteredItems = this.selectorItems.filter((item) => { - return item.name.toLowerCase().includes(searchText) - }).sort(walletsSort) + this.filteredItems = this.selectorItems + .filter((item) => { + return item.name.toLowerCase().includes(searchText) + }) + .sort(walletsSort) } renderSelectorItems() { diff --git a/sdk/packages/selector-base/src/modal.ts b/sdk/packages/selector-base/src/modal.ts index 36d3f3c3..636fce3a 100644 --- a/sdk/packages/selector-base/src/modal.ts +++ b/sdk/packages/selector-base/src/modal.ts @@ -45,6 +45,10 @@ export class NightlyConnectSelectorModal { } } + set sessionId(id: string) { + if (this._modal && id) this._modal.sessionId = id + } + createSelectorElement = ( variablesOverride?: object, stylesOverride?: string, @@ -67,10 +71,13 @@ export class NightlyConnectSelectorModal { } } - public openModal = (sessionId: string, onSelectListWallet: (name: string) => void) => { + public openModal = ( + sessionId: string | undefined, + onSelectListWallet: (name: string) => void + ) => { if (this._modal && this._open === false) { this._modal.onWalletClick = onSelectListWallet - this._modal.sessionId = sessionId + this._modal.sessionId = sessionId ?? '' this._anchor.appendChild(this._modal) this._open = true this.onOpen?.() diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 7b734b81..d2f9199c 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -449,6 +449,40 @@ export class NightlyConnectAdapter implements Injected { return } + if (this._modal) { + this._modal.onClose = () => { + if (this._connecting) { + this._connecting = false + const error = new Error('Connection cancelled') + reject(error) + } + } + this._modal.openModal(this._app?.sessionId ?? undefined, (walletName: string) => { + if ( + isMobileBrowser() && + !this.walletsList.find((w) => w.name === walletName)?.injectedWallet + ) { + this.connectToMobileWallet(walletName) + } else { + this.connectToStandardWallet(walletName, resolve) + } + }) + + let checks = 0 + let intervalId = setInterval((): void => { + checks++ + if (this._app && this._modal) { + this._modal.sessionId = this._app.sessionId + clearInterval(intervalId) + } + + if (checks > 1000) { + clearInterval(intervalId) + reject(new Error('Connecting takes too long')) + } + }, 10) + } + if (this._initOnConnect) { this._connecting = true @@ -547,25 +581,6 @@ export class NightlyConnectAdapter implements Injected { } }) - if (this._modal) { - this._modal.onClose = () => { - if (this._connecting) { - this._connecting = false - const error = new Error('Connection cancelled') - reject(error) - } - } - this._modal.openModal(this._app.sessionId, (walletName: string) => { - if ( - isMobileBrowser() && - !this.walletsList.find((w) => w.name === walletName)?.injectedWallet - ) { - this.connectToMobileWallet(walletName) - } else { - this.connectToStandardWallet(walletName, resolve) - } - }) - } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { this._connecting = false From 4977ecc316a8165ce6219b66220924818c0771cd Mon Sep 17 00:00:00 2001 From: LukassF Date: Thu, 15 Feb 2024 13:19:24 +0100 Subject: [PATCH 02/13] fix: linter changes --- .../nightly-wallet-selector-page.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts b/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts index a0225e9d..ce64a2e8 100644 --- a/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts +++ b/sdk/packages/modal/src/components/nightly-wallet-selector-page/nightly-wallet-selector-page.ts @@ -46,11 +46,9 @@ export class NightlyWalletSelectorPage extends LitElement { const searchText = searchInput.value.toLowerCase() this.searchText = searchText - this.filteredItems = this.selectorItems - .filter((item) => { - return item.name.toLowerCase().includes(searchText) - }) - .sort(walletsSort) + this.filteredItems = this.selectorItems.filter((item) => { + return item.name.toLowerCase().includes(searchText) + }).sort(walletsSort) } renderSelectorItems() { From 0e09bfa269d2a24db82465274d91a22a529d82f8 Mon Sep 17 00:00:00 2001 From: LukassF Date: Thu, 15 Feb 2024 16:34:35 +0100 Subject: [PATCH 03/13] fix: mobile initial loading --- .../nightly-mobile-main.ts | 32 ++--- sdk/packages/selector-polkadot/src/adapter.ts | 120 ++++++++---------- 2 files changed, 65 insertions(+), 87 deletions(-) diff --git a/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts b/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts index 72f5edb2..e74c5a5a 100644 --- a/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts +++ b/sdk/packages/modal/src/components/nightly-mobile-main/nightly-mobile-main.ts @@ -1,6 +1,6 @@ import { customElement, property, state } from 'lit/decorators.js' import { tailwindElement } from '../../shared/tailwind.element' -import { LitElement, PropertyValueMap, html } from 'lit' +import { LitElement, html } from 'lit' import { walletsSort } from '../../utils/utils' import style from './nightly-mobile-main.css' import { WalletSelectorItem } from '../../utils/types' @@ -20,19 +20,19 @@ export class NightlyMobileMain extends LitElement { // eslint-disable-next-line @typescript-eslint/no-empty-function openQrPage: () => void = () => {} - // private _selectorItems: WalletSelectorItem[] = [] + private _selectorItems: WalletSelectorItem[] = [] @property({ type: Array }) - selectorItems: WalletSelectorItem[] = [] - // get selectorItems(): WalletSelectorItem[] { - // return this._selectorItems - // } + get selectorItems(): WalletSelectorItem[] { + return this._selectorItems + } - // set selectorItems(value: WalletSelectorItem[]) { - // this._selectorItems = [...value].sort(walletsSort) + set selectorItems(value: WalletSelectorItem[]) { + this._selectorItems = [...value].sort(walletsSort) - // this.setItemsCount() - // } + this.setItemsCount() + this.requestUpdate() + } @state() numberOfItems = 2 @@ -61,18 +61,6 @@ export class NightlyMobileMain extends LitElement { this.smallestMobileQuery.addEventListener('change', this.setItemsCount) } - protected updated(_changedProperties: PropertyValueMap | Map): void { - const prevSelectorItems: WalletSelectorItem[] = _changedProperties.get('selectorItems') - - if ( - prevSelectorItems && - !this.selectorItems.filter( - (item) => !prevSelectorItems.find((wallet) => wallet.name === item.name) - ).length - ) - this.selectorItems = [...this.selectorItems].sort(walletsSort) - } - render() { return html`
diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index d2f9199c..703ccb05 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -449,8 +449,13 @@ export class NightlyConnectAdapter implements Injected { return } + let intervalId: NodeJS.Timeout + + // opening modal and waiting for sessionId if (this._modal) { this._modal.onClose = () => { + clearInterval(intervalId) + if (this._connecting) { this._connecting = false const error = new Error('Connection cancelled') @@ -463,19 +468,23 @@ export class NightlyConnectAdapter implements Injected { !this.walletsList.find((w) => w.name === walletName)?.injectedWallet ) { this.connectToMobileWallet(walletName) + clearInterval(intervalId) } else { this.connectToStandardWallet(walletName, resolve) + clearInterval(intervalId) } }) + // checking whether sessionId is defined let checks = 0 - let intervalId = setInterval((): void => { + intervalId = setInterval((): void => { checks++ if (this._app && this._modal) { this._modal.sessionId = this._app.sessionId clearInterval(intervalId) } + // fallback when connecting takes too long if (checks > 1000) { clearInterval(intervalId) reject(new Error('Connecting takes too long')) @@ -507,79 +516,60 @@ export class NightlyConnectAdapter implements Injected { throw e } } - } else { - if (this._loading) { - // we do it to ensure proper connect flow in case if adapter is lazily built, but e. g. polkadot wallets selector uses its own eager connect - for (let i = 0; i < 200; i++) { - await sleep(10) - - if (!this._loading) { - break - } - } - - if (this._loading) { - throw new Error('Wallet not ready') - } - } - - if (!this._app) { - throw new Error('Wallet not ready') - } - - this._connecting = true } - if (this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { - // Try to eager connect if session is restored - try { - this.eagerConnectDeeplink() - this._connected = true - this._connecting = false - this._appSessionActive = true - resolve() - return - } catch (error) { - // If we fail because of whatever reason - // Reset session since it might be corrupted - const [app] = await NightlyConnectAdapter.initApp(this._appInitData) - this._app = app + if (this._app) { + if (this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { + // Try to eager connect if session is restored + try { + this.eagerConnectDeeplink() + this._connected = true + this._connecting = false + this._appSessionActive = true + resolve() + return + } catch (error) { + // If we fail because of whatever reason + // Reset session since it might be corrupted + const [app] = await NightlyConnectAdapter.initApp(this._appInitData) + this._app = app + } } - } - const recentName = getRecentStandardWalletForNetwork(this.network) - if ( - this._useEagerConnect && - recentName !== null && - isStandardConnectedForNetwork(this.network) - ) { - await this.connectToStandardWallet(recentName, resolve) + const recentName = getRecentStandardWalletForNetwork(this.network) + if ( + this._useEagerConnect && + recentName !== null && + isStandardConnectedForNetwork(this.network) + ) { + await this.connectToStandardWallet(recentName, resolve) - if (this._connected) { - return - } - } - this._app.on('userConnected', () => { - try { - if (this._chosenMobileWalletName) { - persistRecentStandardWalletForNetwork(this._chosenMobileWalletName, this.network) - } else { - clearRecentStandardWalletForNetwork(this.network) + if (this._connected) { + return } - if (!this._app || this._app.accounts.activeAccounts.length <= 0) { + } + this._app.on('userConnected', () => { + try { + if (this._chosenMobileWalletName) { + persistRecentStandardWalletForNetwork(this._chosenMobileWalletName, this.network) + } else { + clearRecentStandardWalletForNetwork(this.network) + } + if (!this._app || this._app.accounts.activeAccounts.length <= 0) { + this._connecting = false + // If user does not pass any accounts, we should disconnect + this.disconnect() + } + this._connected = true this._connecting = false - // If user does not pass any accounts, we should disconnect + this._appSessionActive = true + this._modal?.closeModal() + resolve() + } catch { this.disconnect() } - this._connected = true - this._connecting = false - this._appSessionActive = true - this._modal?.closeModal() - resolve() - } catch { - this.disconnect() - } - }) + }) + } // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { From 94a7e2fcce422873480bda9bb65b6766fa1e5181 Mon Sep 17 00:00:00 2001 From: LukassF Date: Fri, 16 Feb 2024 10:42:24 +0100 Subject: [PATCH 04/13] fix: polkadot app listener not mounting --- sdk/packages/selector-polkadot/src/adapter.ts | 128 +++++++++--------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 703ccb05..058b3164 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -454,7 +454,7 @@ export class NightlyConnectAdapter implements Injected { // opening modal and waiting for sessionId if (this._modal) { this._modal.onClose = () => { - clearInterval(intervalId) + if (intervalId) clearInterval(intervalId) if (this._connecting) { this._connecting = false @@ -468,25 +468,82 @@ export class NightlyConnectAdapter implements Injected { !this.walletsList.find((w) => w.name === walletName)?.injectedWallet ) { this.connectToMobileWallet(walletName) - clearInterval(intervalId) + if (intervalId) clearInterval(intervalId) } else { this.connectToStandardWallet(walletName, resolve) - clearInterval(intervalId) + if (intervalId) clearInterval(intervalId) } }) // checking whether sessionId is defined let checks = 0 - intervalId = setInterval((): void => { + intervalId = setInterval(async (): Promise => { checks++ - if (this._app && this._modal) { - this._modal.sessionId = this._app.sessionId - clearInterval(intervalId) + if (this._app) { + if (this._modal) this._modal.sessionId = this._app.sessionId + if (intervalId) clearInterval(intervalId) + + if (this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { + // Try to eager connect if session is restored + try { + this.eagerConnectDeeplink() + this._connected = true + this._connecting = false + this._appSessionActive = true + resolve() + return + } catch (error) { + // If we fail because of whatever reason + // Reset session since it might be corrupted + const [app] = await NightlyConnectAdapter.initApp(this._appInitData) + this._app = app + } + } + + const recentName = getRecentStandardWalletForNetwork(this.network) + if ( + this._useEagerConnect && + recentName !== null && + isStandardConnectedForNetwork(this.network) + ) { + await this.connectToStandardWallet(recentName, resolve) + + if (this._connected) { + return + } + } + + this._app.on('userConnected', () => { + try { + if (this._chosenMobileWalletName) { + persistRecentStandardWalletForNetwork( + this._chosenMobileWalletName, + this.network + ) + } else { + clearRecentStandardWalletForNetwork(this.network) + } + if (!this._app || this._app.accounts.activeAccounts.length <= 0) { + this._connecting = false + // If user does not pass any accounts, we should disconnect + this.disconnect() + } + this._connected = true + this._connecting = false + this._appSessionActive = true + this._modal?.closeModal() + resolve() + } catch { + this.disconnect() + } + }) + + return } // fallback when connecting takes too long - if (checks > 1000) { - clearInterval(intervalId) + if (checks > 500) { + if (intervalId) clearInterval(intervalId) reject(new Error('Connecting takes too long')) } }, 10) @@ -518,59 +575,6 @@ export class NightlyConnectAdapter implements Injected { } } - if (this._app) { - if (this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { - // Try to eager connect if session is restored - try { - this.eagerConnectDeeplink() - this._connected = true - this._connecting = false - this._appSessionActive = true - resolve() - return - } catch (error) { - // If we fail because of whatever reason - // Reset session since it might be corrupted - const [app] = await NightlyConnectAdapter.initApp(this._appInitData) - this._app = app - } - } - - const recentName = getRecentStandardWalletForNetwork(this.network) - if ( - this._useEagerConnect && - recentName !== null && - isStandardConnectedForNetwork(this.network) - ) { - await this.connectToStandardWallet(recentName, resolve) - - if (this._connected) { - return - } - } - this._app.on('userConnected', () => { - try { - if (this._chosenMobileWalletName) { - persistRecentStandardWalletForNetwork(this._chosenMobileWalletName, this.network) - } else { - clearRecentStandardWalletForNetwork(this.network) - } - if (!this._app || this._app.accounts.activeAccounts.length <= 0) { - this._connecting = false - // If user does not pass any accounts, we should disconnect - this.disconnect() - } - this._connected = true - this._connecting = false - this._appSessionActive = true - this._modal?.closeModal() - resolve() - } catch { - this.disconnect() - } - }) - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { this._connecting = false From 8d5acbf16f51d2370cb4c71c0053b023f47f176d Mon Sep 17 00:00:00 2001 From: LukassF Date: Fri, 16 Feb 2024 15:13:35 +0100 Subject: [PATCH 05/13] fix: polkadot eager connect no modal --- sdk/apps/modal-example/src/routes/aleph.tsx | 2 +- sdk/packages/selector-base/src/persistence.ts | 39 ++--- sdk/packages/selector-base/src/types.ts | 5 + sdk/packages/selector-polkadot/src/adapter.ts | 133 +++++++++--------- 4 files changed, 82 insertions(+), 97 deletions(-) diff --git a/sdk/apps/modal-example/src/routes/aleph.tsx b/sdk/apps/modal-example/src/routes/aleph.tsx index aa506d34..bec6ec39 100644 --- a/sdk/apps/modal-example/src/routes/aleph.tsx +++ b/sdk/apps/modal-example/src/routes/aleph.tsx @@ -28,7 +28,7 @@ export default function Polkadot() { document.getElementById('modalAnchor') ) - adapter.canEagerConnect().then((canEagerConnect) => { + adapter.canEagerConnect().then((canEagerConnect: boolean) => { setEager(canEagerConnect) }) setAdapter(adapter) diff --git a/sdk/packages/selector-base/src/persistence.ts b/sdk/packages/selector-base/src/persistence.ts index 4cbb047d..984135c9 100644 --- a/sdk/packages/selector-base/src/persistence.ts +++ b/sdk/packages/selector-base/src/persistence.ts @@ -1,8 +1,14 @@ import { getSessionIdLocalStorageKey } from '@nightlylabs/nightly-connect-base' import { ILocalStorage, getStorage } from 'isomorphic-localstorage' +import { AccountWalletType } from './types' let _localStorage: ILocalStorage | null = null +type WalletInfo = { + walletName: string + walletType: AccountWalletType +} + export const getLocalStorage = () => { if (_localStorage === null) { _localStorage = getStorage('./nightly-connect-session') @@ -13,13 +19,16 @@ export const getLocalStorage = () => { // recent wallet from standard -export const persistRecentStandardWalletForNetwork = (walletName: string, network: string) => { +export const persistRecentWalletForNetwork = (network: string, walletInfo: WalletInfo) => { const storage = getLocalStorage() - storage.setItem('NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network, walletName) + storage.setItem( + 'NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network, + JSON.stringify(walletInfo) + ) } -export const getRecentStandardWalletForNetwork = (network: string) => { +export const getRecentWalletForNetwork = (network: string) => { const storage = getLocalStorage() const item = storage.getItem('NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network) @@ -27,7 +36,7 @@ export const getRecentStandardWalletForNetwork = (network: string) => { return item } -export const clearRecentStandardWalletForNetwork = (network: string) => { +export const clearRecentWalletForNetwork = (network: string) => { const storage = getLocalStorage() storage.removeItem('NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network) @@ -40,25 +49,3 @@ export const clearSessionIdForNetwork = (network: string) => { storage.removeItem(getSessionIdLocalStorageKey(network)) } - -// info if any wallet from standard is connected - -export const persistStandardConnectForNetwork = (network: string) => { - const storage = getLocalStorage() - - storage.setItem('NIGHTLY_CONNECT_SELECTOR_IS_DESKTOP_CONNECTED_' + network, 'true') -} - -export const isStandardConnectedForNetwork = (network: string) => { - const storage = getLocalStorage() - - const item = storage.getItem('NIGHTLY_CONNECT_SELECTOR_IS_DESKTOP_CONNECTED_' + network) - - return item !== null -} - -export const persistStandardDisconnectForNetwork = (network: string) => { - const storage = getLocalStorage() - - storage.removeItem('NIGHTLY_CONNECT_SELECTOR_IS_DESKTOP_CONNECTED_' + network) -} diff --git a/sdk/packages/selector-base/src/types.ts b/sdk/packages/selector-base/src/types.ts index 67d731c7..aee8a263 100644 --- a/sdk/packages/selector-base/src/types.ts +++ b/sdk/packages/selector-base/src/types.ts @@ -32,3 +32,8 @@ export enum ConnectionType { Nightly = 'Nightly', WalletStandard = 'WalletStandard' } + +export enum AccountWalletType { + Standard = 'Standard', + Relay = 'Relay' +} diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 058b3164..4878b3c1 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -7,17 +7,18 @@ import { import { NightlyConnectSelectorModal, XMLOptions, - clearRecentStandardWalletForNetwork, + clearRecentWalletForNetwork, clearSessionIdForNetwork, - getRecentStandardWalletForNetwork, + getRecentWalletForNetwork, isMobileBrowser, - isStandardConnectedForNetwork, + // isStandardConnectedForNetwork, logoBase64, - persistRecentStandardWalletForNetwork, - persistStandardConnectForNetwork, - persistStandardDisconnectForNetwork, + persistRecentWalletForNetwork, + // persistStandardConnectForNetwork, + // persistStandardDisconnectForNetwork, sleep, - triggerConnect + triggerConnect, + AccountWalletType } from '@nightlylabs/wallet-selector-base' import { type Signer as InjectedSigner } from '@polkadot/api/types' @@ -157,7 +158,7 @@ export class NightlyConnectAdapter implements Injected { adapter.walletsList = getPolkadotWalletsList( [], - getRecentStandardWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network) ?? undefined ) adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, @@ -176,7 +177,7 @@ export class NightlyConnectAdapter implements Injected { adapter.walletsList = getPolkadotWalletsList( metadataWallets, - getRecentStandardWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network) ?? undefined ) return adapter @@ -200,7 +201,7 @@ export class NightlyConnectAdapter implements Injected { adapter.walletsList = getPolkadotWalletsList( [], - getRecentStandardWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network) ?? undefined ) adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, @@ -220,7 +221,7 @@ export class NightlyConnectAdapter implements Injected { adapter._metadataWallets = metadataWallets adapter.walletsList = getPolkadotWalletsList( metadataWallets, - getRecentStandardWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network) ?? undefined ) adapter._loading = false @@ -250,7 +251,7 @@ export class NightlyConnectAdapter implements Injected { adapter.walletsList = getPolkadotWalletsList( [], - getRecentStandardWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network) ?? undefined ) adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, @@ -266,9 +267,7 @@ export class NightlyConnectAdapter implements Injected { } // ensureLoaded = async () => {} canEagerConnect = async () => { - if (!this._useEagerConnect) { - return false - } + if (getRecentWalletForNetwork(this.network) == null || !this._useEagerConnect) return false // utility for case if somebody wants to fire connect asap, but doesn't want to show modal if e. g. there was no user connected on the device yet if (this._loading) { @@ -289,19 +288,14 @@ export class NightlyConnectAdapter implements Injected { return true } - if ( - getRecentStandardWalletForNetwork(this.network) !== null && - isStandardConnectedForNetwork(this.network) - ) { - return true - } + if (getRecentWalletForNetwork(this.network) !== null) return true return false } eagerConnectDeeplink = () => { if (isMobileBrowser() && this._app) { - const mobileWalletName = getRecentStandardWalletForNetwork(this.network) + const mobileWalletName = getRecentWalletForNetwork(this.network) const wallet = this.walletsList.find((w) => w.name === mobileWalletName) if (typeof wallet === 'undefined') { @@ -411,8 +405,11 @@ export class NightlyConnectAdapter implements Injected { throw new Error('No accounts found') } - persistRecentStandardWalletForNetwork(walletName, this.network) - persistStandardConnectForNetwork(this.network) + persistRecentWalletForNetwork(this.network, { + walletName, + walletType: AccountWalletType.Standard + }) + // persistStandardConnectForNetwork(this.network) this._innerStandardAdapter = { ...inject, signer: { @@ -433,7 +430,7 @@ export class NightlyConnectAdapter implements Injected { onSuccess() } catch { // clear recent wallet - persistStandardDisconnectForNetwork(this.network) + clearRecentWalletForNetwork(this.network) if (this._modal) { this._modal.setStandardWalletConnectProgress(false) } @@ -449,12 +446,38 @@ export class NightlyConnectAdapter implements Injected { return } - let intervalId: NodeJS.Timeout + const recentWallet = getRecentWalletForNetwork(this.network) + if (this._useEagerConnect && recentWallet !== null) { + await this.connectToStandardWallet(JSON.parse(recentWallet).walletName, resolve) + + if (this._connected) { + return resolve() + } + } + + if (this._app?.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { + // Try to eager connect if session is restored + try { + this.eagerConnectDeeplink() + this._connected = true + this._connecting = false + this._appSessionActive = true + resolve() + return + } catch (error) { + // If we fail because of whatever reason + // Reset session since it might be corrupted + const [app] = await NightlyConnectAdapter.initApp(this._appInitData) + this._app = app + } + } + + let loadingInterval: NodeJS.Timeout // opening modal and waiting for sessionId if (this._modal) { this._modal.onClose = () => { - if (intervalId) clearInterval(intervalId) + clearInterval(loadingInterval) if (this._connecting) { this._connecting = false @@ -468,60 +491,30 @@ export class NightlyConnectAdapter implements Injected { !this.walletsList.find((w) => w.name === walletName)?.injectedWallet ) { this.connectToMobileWallet(walletName) - if (intervalId) clearInterval(intervalId) + clearInterval(loadingInterval) } else { this.connectToStandardWallet(walletName, resolve) - if (intervalId) clearInterval(intervalId) + clearInterval(loadingInterval) } }) // checking whether sessionId is defined let checks = 0 - intervalId = setInterval(async (): Promise => { + loadingInterval = setInterval(async (): Promise => { checks++ if (this._app) { if (this._modal) this._modal.sessionId = this._app.sessionId - if (intervalId) clearInterval(intervalId) - - if (this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { - // Try to eager connect if session is restored - try { - this.eagerConnectDeeplink() - this._connected = true - this._connecting = false - this._appSessionActive = true - resolve() - return - } catch (error) { - // If we fail because of whatever reason - // Reset session since it might be corrupted - const [app] = await NightlyConnectAdapter.initApp(this._appInitData) - this._app = app - } - } - - const recentName = getRecentStandardWalletForNetwork(this.network) - if ( - this._useEagerConnect && - recentName !== null && - isStandardConnectedForNetwork(this.network) - ) { - await this.connectToStandardWallet(recentName, resolve) - - if (this._connected) { - return - } - } + clearInterval(loadingInterval) this._app.on('userConnected', () => { try { if (this._chosenMobileWalletName) { - persistRecentStandardWalletForNetwork( - this._chosenMobileWalletName, - this.network - ) + persistRecentWalletForNetwork(this.network, { + walletName: this._chosenMobileWalletName, + walletType: AccountWalletType.Standard + }) } else { - clearRecentStandardWalletForNetwork(this.network) + clearRecentWalletForNetwork(this.network) } if (!this._app || this._app.accounts.activeAccounts.length <= 0) { this._connecting = false @@ -543,7 +536,7 @@ export class NightlyConnectAdapter implements Injected { // fallback when connecting takes too long if (checks > 500) { - if (intervalId) clearInterval(intervalId) + clearInterval(loadingInterval) reject(new Error('Connecting takes too long')) } }, 10) @@ -563,7 +556,7 @@ export class NightlyConnectAdapter implements Injected { this.walletsList = getPolkadotWalletsList( metadataWallets, - getRecentStandardWalletForNetwork(this.network) ?? undefined + getRecentWalletForNetwork(this.network) ?? undefined ) } catch (e) { this._connecting = false @@ -593,12 +586,12 @@ export class NightlyConnectAdapter implements Injected { this._app = await AppPolkadot.build(this._appInitData) if (this._innerStandardAdapter) { this._innerStandardAdapter = undefined - persistStandardDisconnectForNetwork(this.network) + clearRecentWalletForNetwork(this.network) } // Update recent wallet this.walletsList = getPolkadotWalletsList( this._metadataWallets, - getRecentStandardWalletForNetwork(this.network) ?? undefined + getRecentWalletForNetwork(this.network) ?? undefined ) if (this._modal) { this._modal.walletsList = this.walletsList From f4cd58daac9ab9c072b351da9e36d0250d8e46ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Mon, 19 Feb 2024 16:39:36 +0100 Subject: [PATCH 06/13] fiexes + options connection --- sdk/apps/modal-example/package.json | 2 +- sdk/apps/modal-example/src/routes/aleph.tsx | 7 +- sdk/packages/selector-base/package.json | 2 +- sdk/packages/selector-base/src/persistence.ts | 28 +- sdk/packages/selector-base/src/types.ts | 12 +- sdk/packages/selector-polkadot/package.json | 4 +- sdk/packages/selector-polkadot/src/adapter.ts | 463 ++++++++---------- sdk/pnpm-lock.yaml | 6 +- 8 files changed, 246 insertions(+), 278 deletions(-) diff --git a/sdk/apps/modal-example/package.json b/sdk/apps/modal-example/package.json index cf589391..0f5dbf66 100644 --- a/sdk/apps/modal-example/package.json +++ b/sdk/apps/modal-example/package.json @@ -22,7 +22,7 @@ "@nightlylabs/nightly-connect-sui": "0.0.29", "@nightlylabs/wallet-selector-sui": "0.2.7", "@nightlylabs/nightly-connect-polkadot": "0.0.14", - "@nightlylabs/wallet-selector-polkadot": "0.1.19", + "@nightlylabs/wallet-selector-polkadot": "0.2.0", "@polkadot/extension-inject": "^0.46.5", "@polkadot/api": "^10.10.1", "@solana/web3.js": "^1.77.2", diff --git a/sdk/apps/modal-example/src/routes/aleph.tsx b/sdk/apps/modal-example/src/routes/aleph.tsx index bec6ec39..ed5ea9e6 100644 --- a/sdk/apps/modal-example/src/routes/aleph.tsx +++ b/sdk/apps/modal-example/src/routes/aleph.tsx @@ -22,13 +22,14 @@ export default function Polkadot() { icon: 'https://docs.nightly.app/img/logo.png', additionalInfo: 'Courtesy of Nightly Connect team' }, - network: 'AlephZero' + network: 'AlephZero', + persistent: true }, - true, // change this to false to test disabling eager connect - document.getElementById('modalAnchor') + { initOnConnect: false, disableModal: false, disableEagerConnect: false } ) adapter.canEagerConnect().then((canEagerConnect: boolean) => { + console.log('canEagerConnect', canEagerConnect) setEager(canEagerConnect) }) setAdapter(adapter) diff --git a/sdk/packages/selector-base/package.json b/sdk/packages/selector-base/package.json index 78473d37..034bfb63 100644 --- a/sdk/packages/selector-base/package.json +++ b/sdk/packages/selector-base/package.json @@ -1,6 +1,6 @@ { "name": "@nightlylabs/wallet-selector-base", - "version": "0.2.5", + "version": "0.3.0", "description": "", "type": "module", "exports": { diff --git a/sdk/packages/selector-base/src/persistence.ts b/sdk/packages/selector-base/src/persistence.ts index 984135c9..a563ac3c 100644 --- a/sdk/packages/selector-base/src/persistence.ts +++ b/sdk/packages/selector-base/src/persistence.ts @@ -1,12 +1,12 @@ import { getSessionIdLocalStorageKey } from '@nightlylabs/nightly-connect-base' import { ILocalStorage, getStorage } from 'isomorphic-localstorage' -import { AccountWalletType } from './types' +import { ConnectionType } from './types' let _localStorage: ILocalStorage | null = null type WalletInfo = { walletName: string - walletType: AccountWalletType + walletType: ConnectionType } export const getLocalStorage = () => { @@ -18,34 +18,32 @@ export const getLocalStorage = () => { } // recent wallet from standard - +export const NIGHTLY_CONNECT_RECENT_WALLET = 'NIGHTLY_CONNECT_RECENT_WALLET_' export const persistRecentWalletForNetwork = (network: string, walletInfo: WalletInfo) => { const storage = getLocalStorage() - - storage.setItem( - 'NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network, - JSON.stringify(walletInfo) - ) + storage.setItem(NIGHTLY_CONNECT_RECENT_WALLET + network, JSON.stringify(walletInfo)) } export const getRecentWalletForNetwork = (network: string) => { const storage = getLocalStorage() - - const item = storage.getItem('NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network) - - return item + const item = storage.getItem(NIGHTLY_CONNECT_RECENT_WALLET + network) + if (!item) return null + try { + return JSON.parse(item) as WalletInfo + } catch (error) { + console.warn('Error parsing recent wallet from local storage', error) + return null + } } export const clearRecentWalletForNetwork = (network: string) => { const storage = getLocalStorage() - - storage.removeItem('NIGHTLY_CONNECT_SELECTOR_RECENT_STANDARD_WALLET_' + network) + storage.removeItem(NIGHTLY_CONNECT_RECENT_WALLET + network) } // clearing last nightly connect session id export const clearSessionIdForNetwork = (network: string) => { const storage = getLocalStorage() - storage.removeItem(getSessionIdLocalStorageKey(network)) } diff --git a/sdk/packages/selector-base/src/types.ts b/sdk/packages/selector-base/src/types.ts index aee8a263..0a14a253 100644 --- a/sdk/packages/selector-base/src/types.ts +++ b/sdk/packages/selector-base/src/types.ts @@ -33,7 +33,13 @@ export enum ConnectionType { WalletStandard = 'WalletStandard' } -export enum AccountWalletType { - Standard = 'Standard', - Relay = 'Relay' +export interface ConnectionOptions { + disableModal?: boolean // default: false + initOnConnect?: boolean // default: false + disableEagerConnect?: boolean // default: false +} +export const defaultConnectionOptions: ConnectionOptions = { + disableModal: false, + initOnConnect: false, + disableEagerConnect: false } diff --git a/sdk/packages/selector-polkadot/package.json b/sdk/packages/selector-polkadot/package.json index 96293bd0..030dba3f 100644 --- a/sdk/packages/selector-polkadot/package.json +++ b/sdk/packages/selector-polkadot/package.json @@ -1,6 +1,6 @@ { "name": "@nightlylabs/wallet-selector-polkadot", - "version": "0.1.19", + "version": "0.2.0", "description": "", "type": "module", "exports": { @@ -25,7 +25,7 @@ "license": "ISC", "dependencies": { "@nightlylabs/nightly-connect-polkadot": "^0.0.15", - "@nightlylabs/wallet-selector-base": "^0.2.5", + "@nightlylabs/wallet-selector-base": "^0.3.0", "@polkadot/extension-inject": "0.46.5", "@polkadot/api": "10.10.1", "@wallet-standard/core": "^1.0.3" diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 4878b3c1..e7384db6 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -5,20 +5,19 @@ import { WalletMetadata } from '@nightlylabs/nightly-connect-polkadot' import { + ConnectionOptions, + ConnectionType, NightlyConnectSelectorModal, XMLOptions, clearRecentWalletForNetwork, clearSessionIdForNetwork, + defaultConnectionOptions, getRecentWalletForNetwork, isMobileBrowser, - // isStandardConnectedForNetwork, logoBase64, persistRecentWalletForNetwork, - // persistStandardConnectForNetwork, - // persistStandardDisconnectForNetwork, sleep, - triggerConnect, - AccountWalletType + triggerConnect } from '@nightlylabs/wallet-selector-base' import { type Signer as InjectedSigner } from '@polkadot/api/types' @@ -35,14 +34,13 @@ export class NightlyConnectAdapter implements Injected { private _connecting: boolean private _connected: boolean + private _connectionOptions: ConnectionOptions = defaultConnectionOptions private _app: AppPolkadot | undefined - private _appSessionActive: boolean private _innerStandardAdapter: Injected | undefined private _modal: NightlyConnectSelectorModal | undefined private _appInitData: AppSelectorInitialize - private _useEagerConnect: boolean private _metadataWallets: WalletMetadata[] = [] private _walletsList: IPolkadotWalletListItem[] = [] @@ -51,20 +49,16 @@ export class NightlyConnectAdapter implements Injected { private _loading: boolean - private _initOnConnect: boolean - - constructor( - appInitData: AppSelectorInitialize, - useEagerConnect?: boolean, - initOnConnect = false - ) { + constructor(appInitData: AppSelectorInitialize, connectionOptions?: ConnectionOptions) { this._connecting = false this._connected = false this._appInitData = appInitData - this._useEagerConnect = !!useEagerConnect - this._appSessionActive = false this._loading = false - this._initOnConnect = initOnConnect + this._connectionOptions = { ...this._connectionOptions, ...connectionOptions } + // If not persistent, clear session id + if (!this._appInitData.persistent) { + clearSessionIdForNetwork(this._appInitData.network) + } } get accounts() { @@ -142,7 +136,7 @@ export class NightlyConnectAdapter implements Injected { public static build = async ( appInitData: AppSelectorInitialize, - useEagerConnect?: boolean, + connectionOptions?: ConnectionOptions, anchorRef?: HTMLElement | null, uiOverrides?: { variablesOverride?: object @@ -150,15 +144,11 @@ export class NightlyConnectAdapter implements Injected { qrConfigOverride?: Partial } ) => { - if (!useEagerConnect) { - clearSessionIdForNetwork(appInitData.network) - } - - const adapter = new NightlyConnectAdapter(appInitData, useEagerConnect) + const adapter = new NightlyConnectAdapter(appInitData, connectionOptions) adapter.walletsList = getPolkadotWalletsList( [], - getRecentWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, @@ -177,7 +167,7 @@ export class NightlyConnectAdapter implements Injected { adapter.walletsList = getPolkadotWalletsList( metadataWallets, - getRecentWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) return adapter @@ -185,7 +175,7 @@ export class NightlyConnectAdapter implements Injected { public static buildLazy = ( appInitData: AppSelectorInitialize, - useEagerConnect?: boolean, + connectionOptions?: ConnectionOptions, anchorRef?: HTMLElement | null, uiOverrides?: { variablesOverride?: object @@ -193,15 +183,11 @@ export class NightlyConnectAdapter implements Injected { qrConfigOverride?: Partial } ) => { - if (!useEagerConnect) { - clearSessionIdForNetwork(appInitData.network) - } - - const adapter = new NightlyConnectAdapter(appInitData, useEagerConnect) + const adapter = new NightlyConnectAdapter(appInitData, connectionOptions) adapter.walletsList = getPolkadotWalletsList( [], - getRecentWalletForNetwork(adapter.network) ?? undefined + getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, @@ -213,179 +199,158 @@ export class NightlyConnectAdapter implements Injected { uiOverrides?.qrConfigOverride ) - adapter._loading = true - - NightlyConnectAdapter.initApp(appInitData) - .then(([app, metadataWallets]) => { - adapter._app = app - adapter._metadataWallets = metadataWallets - adapter.walletsList = getPolkadotWalletsList( - metadataWallets, - getRecentWalletForNetwork(adapter.network) ?? undefined - ) - - adapter._loading = false - }) - .catch(() => { - adapter._loading = false - throw new Error('Failed to initialize adapter') - }) - - return adapter - } - public static buildWithInitOnConnect = ( - appInitData: AppSelectorInitialize, - useEagerConnect?: boolean, - anchorRef?: HTMLElement | null, - uiOverrides?: { - variablesOverride?: object - stylesOverride?: string - qrConfigOverride?: Partial - } - ) => { - if (!useEagerConnect) { - clearSessionIdForNetwork(appInitData.network) + // If init on connect is not enabled, we should initialize app + if (!adapter._connectionOptions.initOnConnect) { + adapter._loading = true + NightlyConnectAdapter.initApp(appInitData) + .then(([app, metadataWallets]) => { + adapter._app = app + adapter._metadataWallets = metadataWallets + adapter.walletsList = getPolkadotWalletsList( + metadataWallets, + getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined + ) + + adapter._loading = false + }) + .catch(() => { + adapter._loading = false + throw new Error('Failed to initialize adapter') + }) } - - const adapter = new NightlyConnectAdapter(appInitData, useEagerConnect, true) - - adapter.walletsList = getPolkadotWalletsList( - [], - getRecentWalletForNetwork(adapter.network) ?? undefined - ) - adapter._modal = new NightlyConnectSelectorModal( - adapter.walletsList, - appInitData.url ?? 'https://nc2.nightly.app', - networkToData(adapter.network), - anchorRef, - uiOverrides?.variablesOverride, - uiOverrides?.stylesOverride, - uiOverrides?.qrConfigOverride - ) - return adapter } - // ensureLoaded = async () => {} - canEagerConnect = async () => { - if (getRecentWalletForNetwork(this.network) == null || !this._useEagerConnect) return false - - // utility for case if somebody wants to fire connect asap, but doesn't want to show modal if e. g. there was no user connected on the device yet - if (this._loading) { - for (let i = 0; i < 200; i++) { - await sleep(10) - if (!this._loading) { - break - } - } - } - - if (this._loading) { - false + // Checks if we can restore user session + canEagerConnect = async () => { + // If eager connect is disabled, we can't eager connect + if (this._connectionOptions.disableEagerConnect) { + return false } - - if (this._app && this._app.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { + // Get recent wallet for network + const recentWallet = getRecentWalletForNetwork(this.network) + console.log({ recentWallet }) + + // If there is no recent wallet, we can't eager connect + if (recentWallet === null) return false + + // If we user wallet standard, we can eager connect + if ( + recentWallet.walletName !== null && + recentWallet.walletType === ConnectionType.WalletStandard + ) { return true } - if (getRecentWalletForNetwork(this.network) !== null) return true + // If we user nightly connect we need to make sure app is restored + if (recentWallet.walletType === ConnectionType.Nightly) { + if (this._connectionOptions.initOnConnect) { + return false + } + // Wait for app to be restored + if (this._loading) { + for (let i = 0; i < 2000; i++) { + await sleep(10) + if (!this._loading) { + break + } + } + } + // If app is restored and has active accounts, we can eager connect + if (this._loading) { + return false + } + if ( + this._app && + this._app.hasBeenRestored() && + this._app.accounts.activeAccounts.length > 0 + ) { + return true + } + } return false } - eagerConnectDeeplink = () => { - if (isMobileBrowser() && this._app) { - const mobileWalletName = getRecentWalletForNetwork(this.network) - const wallet = this.walletsList.find((w) => w.name === mobileWalletName) + connectToMobileWallet = (walletName: string) => { + try { + if (this._modal) { + this._modal.setStandardWalletConnectProgress(true) + } + + const wallet = this.walletsList.find((w) => w.name === walletName) + + if (!this._app) { + throw new Error('Wallet not ready') + } if (typeof wallet === 'undefined') { - return + throw new Error('Wallet not found') } if (wallet.deeplink === null) { - return + throw new Error('Deeplink not found') } + // If we have a native deeplink, we should use it if (wallet.deeplink.native !== null) { this._app.connectDeeplink({ walletName: wallet.name, url: wallet.deeplink.native }) + this._chosenMobileWalletName = walletName + + triggerConnect( + wallet.deeplink.native, + this._app.sessionId, + this._appInitData.url ?? 'https://nc2.nightly.app' + ) return } + // If we have a universal deeplink, we should use it if (wallet.deeplink.universal !== null) { this._app.connectDeeplink({ walletName: wallet.name, url: wallet.deeplink.universal }) - } - } - } - - connectToMobileWallet = (walletName: string) => { - if (this._modal) { - this._modal.setStandardWalletConnectProgress(true) - } - - const wallet = this.walletsList.find((w) => w.name === walletName) - - if (!this._app || typeof wallet === 'undefined') { - return - } - - if (wallet.deeplink === null) { - return - } - - if (wallet.deeplink.native !== null) { - this._app.connectDeeplink({ - walletName: wallet.name, - url: wallet.deeplink.native - }) - - this._chosenMobileWalletName = walletName - - triggerConnect( - wallet.deeplink.native, - this._app.sessionId, - this._appInitData.url ?? 'https://nc2.nightly.app' - ) - - return - } - if (wallet.deeplink.universal !== null) { - this._app.connectDeeplink({ - walletName: wallet.name, - url: wallet.deeplink.universal - }) - - this._chosenMobileWalletName = walletName - - triggerConnect( - wallet.deeplink.universal, - this._app.sessionId, - this._appInitData.url ?? 'https://nc2.nightly.app' - ) - return - } + this._chosenMobileWalletName = walletName - const redirectToAppBrowser = wallet.deeplink.redirectToAppBrowser - if (redirectToAppBrowser !== null && redirectToAppBrowser.indexOf('{{url}}') > -1) { - const url = redirectToAppBrowser.replace( - '{{url}}', - encodeURIComponent(window.location.toString()) - ) - - window.open(url, '_blank', 'noreferrer noopener') - - return + triggerConnect( + wallet.deeplink.universal, + this._app.sessionId, + this._appInitData.url ?? 'https://nc2.nightly.app' + ) + return + } + // Fallback to redirecting to app browser + // aka browser inside the app + if (!wallet.deeplink.redirectToAppBrowser) { + const redirectToAppBrowser = wallet.deeplink.redirectToAppBrowser + if (redirectToAppBrowser !== null && redirectToAppBrowser.indexOf('{{url}}') > -1) { + const url = redirectToAppBrowser.replace( + '{{url}}', + encodeURIComponent(window.location.toString()) + ) + + window.open(url, '_blank', 'noreferrer noopener') + + return + } + } + } catch (err) { + // clear recent wallet + clearRecentWalletForNetwork(this.network) + if (this._modal) { + this._modal.setStandardWalletConnectProgress(false) + } + throw err } } - - connectToStandardWallet = async (walletName: string, onSuccess: () => void) => { + // Generic connect to standard wallet + connectToStandardWallet = async (walletName: string) => { try { if (this._modal) { this._modal.setStandardWalletConnectProgress(true) @@ -404,12 +369,6 @@ export class NightlyConnectAdapter implements Injected { if ((await inject.accounts.get()).length <= 0) { throw new Error('No accounts found') } - - persistRecentWalletForNetwork(this.network, { - walletName, - walletType: AccountWalletType.Standard - }) - // persistStandardConnectForNetwork(this.network) this._innerStandardAdapter = { ...inject, signer: { @@ -424,16 +383,23 @@ export class NightlyConnectAdapter implements Injected { : undefined } } + this._connected = true this._connecting = false + + persistRecentWalletForNetwork(this.network, { + walletName, + walletType: ConnectionType.WalletStandard + }) + this._modal?.closeModal() - onSuccess() - } catch { + } catch (err) { // clear recent wallet clearRecentWalletForNetwork(this.network) if (this._modal) { this._modal.setStandardWalletConnectProgress(false) } + throw err } } @@ -441,137 +407,136 @@ export class NightlyConnectAdapter implements Injected { new Promise((resolve, reject) => { const innerConnect = async () => { try { - if (this.connected || this.connecting) { + if (this._connecting) { + reject("Can't connect while connecting") + return + } + if (this._connected) { resolve() return } const recentWallet = getRecentWalletForNetwork(this.network) - if (this._useEagerConnect && recentWallet !== null) { - await this.connectToStandardWallet(JSON.parse(recentWallet).walletName, resolve) - - if (this._connected) { - return resolve() - } - } - - if (this._app?.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { - // Try to eager connect if session is restored - try { - this.eagerConnectDeeplink() - this._connected = true - this._connecting = false - this._appSessionActive = true + if (!this._connectionOptions.disableEagerConnect && recentWallet !== null) { + // Eager connect standard if possible + if (recentWallet.walletType === ConnectionType.WalletStandard) { + await this.connectToStandardWallet(recentWallet.walletName) resolve() return - } catch (error) { - // If we fail because of whatever reason - // Reset session since it might be corrupted - const [app] = await NightlyConnectAdapter.initApp(this._appInitData) - this._app = app + } + // Eager connect remote if possible + if (recentWallet.walletType === ConnectionType.Nightly) { + if (this._app?.hasBeenRestored() && this._app.accounts.activeAccounts.length > 0) { + // Try to eager connect if session is restored + try { + this._connected = true + this._connecting = false + resolve() + return + } catch (error) { + // If we fail because of whatever reason + // Reset session since it might be corrupted + const [app] = await NightlyConnectAdapter.initApp(this._appInitData) + this._app = app + } + } } } + if (this._connectionOptions.disableModal) { + reject('Modal is disabled') + return + } + if (this._connectionOptions.initOnConnect) { + this._loading = true + NightlyConnectAdapter.initApp(this._appInitData) + .then(([app, metadataWallets]) => { + this._app = app + this._metadataWallets = metadataWallets + this.walletsList = getPolkadotWalletsList( + metadataWallets, + getRecentWalletForNetwork(this.network)?.walletName ?? undefined + ) + this._loading = false + }) + .catch(() => { + this._loading = false + throw new Error('Failed to initialize adapter') + }) + } + // Interval that checks if app has connected let loadingInterval: NodeJS.Timeout // opening modal and waiting for sessionId if (this._modal) { + this._connecting = true this._modal.onClose = () => { clearInterval(loadingInterval) - if (this._connecting) { this._connecting = false const error = new Error('Connection cancelled') reject(error) } } - this._modal.openModal(this._app?.sessionId ?? undefined, (walletName: string) => { + this._modal.openModal(this._app?.sessionId ?? undefined, async (walletName: string) => { if ( isMobileBrowser() && !this.walletsList.find((w) => w.name === walletName)?.injectedWallet ) { this.connectToMobileWallet(walletName) - clearInterval(loadingInterval) } else { - this.connectToStandardWallet(walletName, resolve) - clearInterval(loadingInterval) + await this.connectToStandardWallet(walletName) + resolve() } }) - // checking whether sessionId is defined + // loop until app is connected or we timeout let checks = 0 loadingInterval = setInterval(async (): Promise => { checks++ if (this._app) { - if (this._modal) this._modal.sessionId = this._app.sessionId + // Clear interval if app is connected clearInterval(loadingInterval) - + if (this._modal) this._modal.sessionId = this._app.sessionId this._app.on('userConnected', () => { try { - if (this._chosenMobileWalletName) { - persistRecentWalletForNetwork(this.network, { - walletName: this._chosenMobileWalletName, - walletType: AccountWalletType.Standard - }) - } else { - clearRecentWalletForNetwork(this.network) - } + persistRecentWalletForNetwork(this.network, { + walletName: this._chosenMobileWalletName || '', + walletType: ConnectionType.Nightly + }) + if (!this._app || this._app.accounts.activeAccounts.length <= 0) { this._connecting = false + this._connected = false // If user does not pass any accounts, we should disconnect this.disconnect() + return } this._connected = true this._connecting = false - this._appSessionActive = true this._modal?.closeModal() resolve() } catch { this.disconnect() } }) - return } - // fallback when connecting takes too long + // timeout after 5 seconds if (checks > 500) { clearInterval(loadingInterval) - reject(new Error('Connecting takes too long')) + // reject(new Error('Connecting takes too long')) + // TODO we need to have a way to show error on modal } }, 10) } - - if (this._initOnConnect) { - this._connecting = true - - if (!this._app) { - try { - const [app, metadataWallets] = await NightlyConnectAdapter.initApp( - this._appInitData - ) - - this._app = app - this._metadataWallets = metadataWallets - - this.walletsList = getPolkadotWalletsList( - metadataWallets, - getRecentWalletForNetwork(this.network) ?? undefined - ) - } catch (e) { - this._connecting = false - if (!this._app) { - throw new Error('Wallet not ready') - } - throw e - } - } - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { this._connecting = false reject(error) + } finally { + this._connecting = false } } @@ -582,16 +547,14 @@ export class NightlyConnectAdapter implements Injected { try { // Some apps might use disconnect to reset state / recreate session clearSessionIdForNetwork(this.network) - this._appSessionActive = false + clearRecentWalletForNetwork(this.network) + this._innerStandardAdapter = undefined this._app = await AppPolkadot.build(this._appInitData) - if (this._innerStandardAdapter) { - this._innerStandardAdapter = undefined - clearRecentWalletForNetwork(this.network) - } + // Update recent wallet this.walletsList = getPolkadotWalletsList( this._metadataWallets, - getRecentWalletForNetwork(this.network) ?? undefined + getRecentWalletForNetwork(this.network)?.walletName ?? undefined ) if (this._modal) { this._modal.walletsList = this.walletsList diff --git a/sdk/pnpm-lock.yaml b/sdk/pnpm-lock.yaml index 41dde4ba..55b2d5b7 100644 --- a/sdk/pnpm-lock.yaml +++ b/sdk/pnpm-lock.yaml @@ -141,7 +141,7 @@ importers: specifier: 0.0.29 version: link:../sui '@nightlylabs/wallet-selector-polkadot': - specifier: 0.1.19 + specifier: 0.2.0 version: link:../../packages/selector-polkadot '@nightlylabs/wallet-selector-solana': specifier: 0.2.7 @@ -632,7 +632,7 @@ importers: specifier: ^0.0.15 version: link:../../apps/polkadot '@nightlylabs/wallet-selector-base': - specifier: ^0.2.5 + specifier: ^0.3.0 version: link:../selector-base '@polkadot/api': specifier: 10.10.1 @@ -676,7 +676,7 @@ importers: version: link:../../apps/solana '@nightlylabs/wallet-selector-base': specifier: ^0.2.4 - version: link:../selector-base + version: 0.2.4 '@solana/wallet-adapter-base': specifier: ^0.9.22 version: 0.9.22(@solana/web3.js@1.77.2) From 8c728d09ada347520e07a46e5bb929db9c0e4db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Mon, 19 Feb 2024 17:36:04 +0100 Subject: [PATCH 07/13] add api to connect without modal --- sdk/packages/selector-polkadot/src/adapter.ts | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index e7384db6..4d5c4734 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -150,16 +150,17 @@ export class NightlyConnectAdapter implements Injected { [], getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) - adapter._modal = new NightlyConnectSelectorModal( - adapter.walletsList, - appInitData.url ?? 'https://nc2.nightly.app', - networkToData(adapter.network), - anchorRef, - uiOverrides?.variablesOverride, - uiOverrides?.stylesOverride, - uiOverrides?.qrConfigOverride - ) - + if (!adapter._connectionOptions.disableModal) { + adapter._modal = new NightlyConnectSelectorModal( + adapter.walletsList, + appInitData.url ?? 'https://nc2.nightly.app', + networkToData(adapter.network), + anchorRef, + uiOverrides?.variablesOverride, + uiOverrides?.stylesOverride, + uiOverrides?.qrConfigOverride + ) + } const [app, metadataWallets] = await NightlyConnectAdapter.initApp(appInitData) adapter._app = app @@ -189,15 +190,17 @@ export class NightlyConnectAdapter implements Injected { [], getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) - adapter._modal = new NightlyConnectSelectorModal( - adapter.walletsList, - appInitData.url ?? 'https://nc2.nightly.app', - networkToData(adapter.network), - anchorRef, - uiOverrides?.variablesOverride, - uiOverrides?.stylesOverride, - uiOverrides?.qrConfigOverride - ) + if (!adapter._connectionOptions.disableModal) { + adapter._modal = new NightlyConnectSelectorModal( + adapter.walletsList, + appInitData.url ?? 'https://nc2.nightly.app', + networkToData(adapter.network), + anchorRef, + uiOverrides?.variablesOverride, + uiOverrides?.stylesOverride, + uiOverrides?.qrConfigOverride + ) + } // If init on connect is not enabled, we should initialize app if (!adapter._connectionOptions.initOnConnect) { @@ -402,7 +405,13 @@ export class NightlyConnectAdapter implements Injected { throw err } } - + connectToWallet = async (walletName: string) => { + if (isMobileBrowser() && !this.walletsList.find((w) => w.name === walletName)?.injectedWallet) { + this.connectToMobileWallet(walletName) + } else { + await this.connectToStandardWallet(walletName) + } + } connect = async () => new Promise((resolve, reject) => { const innerConnect = async () => { @@ -479,6 +488,7 @@ export class NightlyConnectAdapter implements Injected { } } this._modal.openModal(this._app?.sessionId ?? undefined, async (walletName: string) => { + // If we are on mobile and wallet is not injected, we should connect to mobile wallet if ( isMobileBrowser() && !this.walletsList.find((w) => w.name === walletName)?.injectedWallet From f30b18736c5ec8929837cc81721cdd399a032d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Mon, 19 Feb 2024 17:39:21 +0100 Subject: [PATCH 08/13] add getters for wallets --- sdk/packages/selector-polkadot/src/adapter.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 4d5c4734..99a94bb0 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -102,6 +102,9 @@ export class NightlyConnectAdapter implements Injected { get network() { return this._appInitData.network } + get walletsFromRegistry() { + return this._metadataWallets + } get walletsList() { return this._walletsList } @@ -552,7 +555,11 @@ export class NightlyConnectAdapter implements Injected { innerConnect() }) - + fetchWalletsFromRegistry = async () => { + return AppPolkadot.getWalletsMetadata( + `${this._appInitData.url ?? 'https://nc2.nightly.app'}/get_wallets_metadata` + ) + } disconnect = async () => { try { // Some apps might use disconnect to reset state / recreate session From 1f29ac03ae0a5a0c19e9d36e20be1ef4fa469634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Mon, 19 Feb 2024 17:54:56 +0100 Subject: [PATCH 09/13] remove logs --- sdk/packages/selector-polkadot/src/adapter.ts | 2 -- .../selector-polkadot/src/detection.ts | 18 +++++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index 99a94bb0..b5cdd0ec 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -235,8 +235,6 @@ export class NightlyConnectAdapter implements Injected { } // Get recent wallet for network const recentWallet = getRecentWalletForNetwork(this.network) - console.log({ recentWallet }) - // If there is no recent wallet, we can't eager connect if (recentWallet === null) return false diff --git a/sdk/packages/selector-polkadot/src/detection.ts b/sdk/packages/selector-polkadot/src/detection.ts index 45394ba5..829a04aa 100644 --- a/sdk/packages/selector-polkadot/src/detection.ts +++ b/sdk/packages/selector-polkadot/src/detection.ts @@ -22,11 +22,11 @@ declare global { export const getPolkadotWallets = (): PolkadotWalletInjected[] => { if (window && window.injectedWeb3) { return Object.entries(window.injectedWeb3).map(([key, value]) => ({ - ...value, - name: value.name ?? key, // value.name might be undefined - slug: key, - icon: value.icon ?? appToIcon[key] ?? 'https://registry.nightly.app/networks/polkadot.png' // TODO add default icon - })) + ...value, + name: value.name ?? key, // value.name might be undefined + slug: key, + icon: value.icon ?? appToIcon[key] ?? 'https://registry.nightly.app/networks/polkadot.png' // TODO add default icon + })) } else { return [] } @@ -52,14 +52,10 @@ export const getPolkadotWalletsList = (presetList: WalletMetadata[], recentWalle recent: recentWalletName === wallet.name } }) - console.log('windowWallets', windowWallets) - console.log('walletsData', walletsData) for (const wallet of windowWallets) { // Check if wallet is already in the list // by namespace if (walletsData[wallet.slug.toLocaleLowerCase()]) { - console.log('a', walletsData[wallet.slug.toLocaleLowerCase()]) - console.log(wallet) walletsData[wallet.slug.toLocaleLowerCase()] = { ...(walletsData?.[wallet.slug.toLocaleLowerCase()] ?? { name: wallet.name, @@ -78,8 +74,6 @@ export const getPolkadotWalletsList = (presetList: WalletMetadata[], recentWalle // Check if wallet is already in the list // by name if (walletsData[wallet.name.toLocaleLowerCase()]) { - console.log('b', walletsData[wallet.name.toLocaleLowerCase()]) - console.log(wallet) walletsData[wallet.name.toLocaleLowerCase()] = { ...(walletsData?.[wallet.name.toLocaleLowerCase()] ?? { name: wallet.name, @@ -94,8 +88,6 @@ export const getPolkadotWalletsList = (presetList: WalletMetadata[], recentWalle } continue } - console.log({ wallet }) - walletsData[wallet.name.toLocaleLowerCase()] = { slug: wallet.name, name: wallet.name, From e8aab83bee15be7663c0488467d43efe813bef3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Tue, 20 Feb 2024 11:46:57 +0100 Subject: [PATCH 10/13] fix connectToWallet api --- sdk/packages/selector-polkadot/src/adapter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index b5cdd0ec..f3769dd8 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -408,9 +408,9 @@ export class NightlyConnectAdapter implements Injected { } connectToWallet = async (walletName: string) => { if (isMobileBrowser() && !this.walletsList.find((w) => w.name === walletName)?.injectedWallet) { - this.connectToMobileWallet(walletName) + return this.connectToMobileWallet(walletName) } else { - await this.connectToStandardWallet(walletName) + return await this.connectToStandardWallet(walletName) } } connect = async () => From 91a1173bc17f6982a4368c35cfcb2a623bd8d603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?NB=F0=9F=98=88?= Date: Tue, 20 Feb 2024 11:50:26 +0100 Subject: [PATCH 11/13] add fetching wallets on lazy load --- sdk/packages/selector-polkadot/src/adapter.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sdk/packages/selector-polkadot/src/adapter.ts b/sdk/packages/selector-polkadot/src/adapter.ts index f3769dd8..72fdf76b 100644 --- a/sdk/packages/selector-polkadot/src/adapter.ts +++ b/sdk/packages/selector-polkadot/src/adapter.ts @@ -193,6 +193,15 @@ export class NightlyConnectAdapter implements Injected { [], getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined ) + // Fetch wallets from registry + adapter.fetchWalletsFromRegistry().then((metadataWallets) => { + adapter._metadataWallets = metadataWallets + adapter.walletsList = getPolkadotWalletsList( + metadataWallets, + getRecentWalletForNetwork(adapter.network)?.walletName ?? undefined + ) + }) + if (!adapter._connectionOptions.disableModal) { adapter._modal = new NightlyConnectSelectorModal( adapter.walletsList, From a39f3a28a52a89b8e1f3a929fbfdc5a0c7372eb3 Mon Sep 17 00:00:00 2001 From: LukassF Date: Tue, 20 Feb 2024 12:37:39 +0100 Subject: [PATCH 12/13] add: modal timeout error page and no loader when session id is immediately defined --- .../nightly-desktop-main.css | 59 +++++++++++++++++ .../nightly-desktop-main.stories.ts | 63 +++++++++++++++---- .../nightly-desktop-main.ts | 51 +++++++++++++-- .../nightly-mobile-qr/nightly-mobile-qr.css | 62 +++++++++++++++++- .../nightly-mobile-qr/nightly-mobile-qr.ts | 50 ++++++++++++++- .../nightly-selector.stories.ts | 37 +++++++++-- 6 files changed, 296 insertions(+), 26 deletions(-) diff --git a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.css b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.css index b65a94b6..51959aef 100644 --- a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.css +++ b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.css @@ -95,6 +95,52 @@ animation: fade_out_loader 250ms ease-out forwards; } +.nc_desktopQrTimeoutErrorOverlay { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: var(--nc-color-elements-2); + z-index: 5; + visibility: hidden; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.nc_desktopQrTimeoutError { + width: 120px; + filter: grayscale(100%) opacity(60%); +} + +.nc_desktopQrTimeoutErrorLabel { + margin-top: 15px; + margin-bottom: 5px; + font-size: 16px; + font-weight: 600; + line-height: 22px; + letter-spacing: 0.02em; + text-align: center; + color: var(--nc-color-elements-7); +} + +.nc_desktopQrTimeoutErrorLabelDescription { + color: var(--nc-color-elements-6); + font-size: 12px; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.02em; + text-align: center; + max-width: 40%; +} + +.nc_desktopQrTimeoutErrorOverlayFadeIn { + visibility: visible; + animation: fade_in_error 250ms ease-out forwards; +} + @media (max-width: 1080px) { .nc_desktopMainWrapper { max-width: 636px; @@ -111,6 +157,10 @@ width: 304px; height: 304px; } + + .nc_desktopQrTimeoutErrorLabelDescription { + max-width: 60%; + } } @keyframes fade_out_loader { @@ -122,3 +172,12 @@ display: none; } } + +@keyframes fade_in_error { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} diff --git a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts index bf2a2683..45601558 100644 --- a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts +++ b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts @@ -14,14 +14,12 @@ import NightlyIcon from '../../static/svg/NightlyIcon.svg' import ChainIcon from '../../static/svg/ChainIcon.svg' import { useArgs } from '@storybook/client-api' - const meta = { title: 'nightly-desktop-main', parameters: { layout: 'centered' }, render: (args) => { - return html`` - } } satisfies Meta @@ -100,17 +97,17 @@ export const Loading: Story = (args: NightlyModalArgs) => { if (!args.sessionId) setTimeout(() => { - updateArgs({ sessionId: "1234" }) + updateArgs({ sessionId: '1234' }) }, 2000) return html`` + .selectorItems=${args.selectorItems} + .onWalletClick=${args.onWalletClick} + .chainIcon=${args.chainIcon} + .chainName=${args.chainName} + .sessionId=${args.sessionId ?? sessionId} + .relay=${args.relay} + >` } Loading.args = { @@ -150,4 +147,46 @@ Loading.args = { chainIcon: ChainIcon, chainName: 'Solana', relay: 'https://nc2.nightly.app' -} \ No newline at end of file +} + +export const Error: Story = { + name: 'Error', + args: { + selectorItems: [ + { name: 'Phantom', icon: Phantom, status: 'recent' }, + { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, + { name: 'MetaMask', icon: MetaMask, status: '' }, + { name: 'Glow', icon: Glow, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: 'detected' }, + { name: 'Trust', icon: Trust, status: '' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Sollet', icon: Sollet, status: '' }, + { name: 'Phantom', icon: Phantom, status: '' }, + { name: 'MetaMask', icon: MetaMask, status: 'recent' }, + { name: 'Coinbase', icon: Coinbase, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: '' }, + { name: 'Trust', icon: Trust, status: 'detected' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Phantom', icon: Phantom, status: 'recent' }, + { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, + { name: 'MetaMask', icon: MetaMask, status: '' }, + { name: 'Glow', icon: Glow, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: 'detected' }, + { name: 'Trust', icon: Trust, status: '' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Sollet', icon: Sollet, status: '' }, + { name: 'Phantom', icon: Phantom, status: '' }, + { name: 'MetaMask', icon: MetaMask, status: 'recent' }, + { name: 'Coinbase', icon: Coinbase, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: '' }, + { name: 'Trust', icon: Trust, status: 'detected' }, + { name: 'Binance', icon: Binance, status: '' } + ], + onWalletClick: (name: string) => { + console.log('Item clicked:', name) + }, + chainIcon: ChainIcon, + chainName: 'Solana', + relay: 'https://nc2.nightly.app' + } +} diff --git a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts index b53666fc..7f9915d2 100644 --- a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts +++ b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts @@ -38,8 +38,16 @@ export class NightlyDesktopMain extends LitElement { @state() qrSource: string | undefined = undefined + @state() + timeoutError: boolean = false + + @state() + isSessionIdImmediatelyDefined: boolean = false + timeoutRef: number | undefined = undefined + loadingTimeout: number | undefined = undefined + onCopy = () => { navigator.clipboard.writeText( 'nc:' + @@ -57,7 +65,8 @@ export class NightlyDesktopMain extends LitElement { } private updateQrSource = () => { - if (this.sessionId) + if (this.sessionId) { + clearTimeout(this.loadingTimeout) this.qrSource = svgToBase64( generateQrCodeXml( 'nc:' + @@ -74,12 +83,30 @@ export class NightlyDesktopMain extends LitElement { } ) ) + } } connectedCallback(): void { super.connectedCallback() + this.loadingTimeout = setTimeout(() => { + if (this.sessionId) clearTimeout(this.loadingTimeout) + // timeout error when sessionId takes longer than 5 seconds to arrive + else { + clearTimeout(this.loadingTimeout) + this.timeoutError = true + } + }, 5000) as unknown as number + this.updateQrSource() + + if (this.sessionId) this.isSessionIdImmediatelyDefined = true + } + + disconnectedCallback(): void { + super.disconnectedCallback() + + clearTimeout(this.loadingTimeout) } protected updated(_changedProperties: PropertyValueMap | Map): void { @@ -106,17 +133,33 @@ export class NightlyDesktopMain extends LitElement {
-
Loading

Generating QR code...

+
`} + +
+ Timeout error +

QR code couldn’t be generated...

+

+ Make sure you have stable internet connection. +

{ - if (this.sessionId) + if (this.sessionId) { + clearTimeout(this.loadingTimeout) + this.qrSource = svgToBase64( generateQrCodeXml( 'nc:' + @@ -45,12 +55,29 @@ export class NightlyMobileQr extends LitElement { } ) ) + } } connectedCallback(): void { super.connectedCallback() + this.loadingTimeout = setTimeout(() => { + if (this.sessionId) clearTimeout(this.loadingTimeout) + // timeout error when sessionId takes longer than 5 seconds to arrive + else { + clearTimeout(this.loadingTimeout) + this.timeoutError = true + } + }, 5000) as unknown as number + this.updateQrSource() + if (this.sessionId) this.isSessionIdImmediatelyDefined = true + } + + disconnectedCallback(): void { + super.disconnectedCallback() + + clearTimeout(this.loadingTimeout) } protected updated(_changedProperties: PropertyValueMap | Map): void { @@ -69,16 +96,33 @@ export class NightlyMobileQr extends LitElement { -
Loading

Generating QR code...

+
`} + +
+ + Timeout error +

QR code couldn’t be generated...

+

+ Make sure you have stable internet connection. +

` diff --git a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts index 0907c131..46c6fcca 100644 --- a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts +++ b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts @@ -114,8 +114,7 @@ Default.args = { 'fsdhfdzfsdhgfzghggdfhbgchgbdfnvfbxhncvfjhzxdhgbhghfgfvzhfgjhgszdhgzxdfhgfzxdjfuhdfhgd', connecting: true, relay: 'https://nc2.nightly.app', - open: true, - + open: true } export const Loading: Story = (args: NightlyModalArgs) => { @@ -126,9 +125,10 @@ export const Loading: Story = (args: NightlyModalArgs) => { args.onClose() } - open && setTimeout(() => { - updateArgs({ sessionId: "1234" }) - }, 2000) + open && + setTimeout(() => { + updateArgs({ sessionId: '1234' }) + }, 2000) return open ? html` @@ -147,4 +147,29 @@ export const Loading: Story = (args: NightlyModalArgs) => { } let { sessionId: _, ...rest } = Default.args -Loading.args = { ...rest } \ No newline at end of file +Loading.args = { ...rest } + +export const Error: Story = (args: NightlyModalArgs) => { + const [{ open }, updateArgs] = useArgs() + + const handleClose = () => { + updateArgs({ open: false }) + args.onClose() + } + + return open + ? html` + + ` + : html`` +} + +Error.args = { ...rest } From 9bcf2164aac2473b342f3b0665e97b7ea3994532 Mon Sep 17 00:00:00 2001 From: LukassF Date: Tue, 20 Feb 2024 13:07:54 +0100 Subject: [PATCH 13/13] fix: timeoutError as a parameter --- .../nightly-desktop-main.stories.ts | 96 +++++++++++-------- .../nightly-desktop-main.ts | 28 +----- .../nightly-mobile-qr/nightly-mobile-qr.ts | 28 +----- .../nightly-selector.stories.ts | 8 +- .../nightly-selector/nightly-selector.ts | 5 + 5 files changed, 76 insertions(+), 89 deletions(-) diff --git a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts index 45601558..53f1a457 100644 --- a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts +++ b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.stories.ts @@ -149,44 +149,60 @@ Loading.args = { relay: 'https://nc2.nightly.app' } -export const Error: Story = { - name: 'Error', - args: { - selectorItems: [ - { name: 'Phantom', icon: Phantom, status: 'recent' }, - { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, - { name: 'MetaMask', icon: MetaMask, status: '' }, - { name: 'Glow', icon: Glow, status: '' }, - { name: 'ZenGO', icon: ZenGO, status: 'detected' }, - { name: 'Trust', icon: Trust, status: '' }, - { name: 'Binance', icon: Binance, status: '' }, - { name: 'Sollet', icon: Sollet, status: '' }, - { name: 'Phantom', icon: Phantom, status: '' }, - { name: 'MetaMask', icon: MetaMask, status: 'recent' }, - { name: 'Coinbase', icon: Coinbase, status: '' }, - { name: 'ZenGO', icon: ZenGO, status: '' }, - { name: 'Trust', icon: Trust, status: 'detected' }, - { name: 'Binance', icon: Binance, status: '' }, - { name: 'Phantom', icon: Phantom, status: 'recent' }, - { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, - { name: 'MetaMask', icon: MetaMask, status: '' }, - { name: 'Glow', icon: Glow, status: '' }, - { name: 'ZenGO', icon: ZenGO, status: 'detected' }, - { name: 'Trust', icon: Trust, status: '' }, - { name: 'Binance', icon: Binance, status: '' }, - { name: 'Sollet', icon: Sollet, status: '' }, - { name: 'Phantom', icon: Phantom, status: '' }, - { name: 'MetaMask', icon: MetaMask, status: 'recent' }, - { name: 'Coinbase', icon: Coinbase, status: '' }, - { name: 'ZenGO', icon: ZenGO, status: '' }, - { name: 'Trust', icon: Trust, status: 'detected' }, - { name: 'Binance', icon: Binance, status: '' } - ], - onWalletClick: (name: string) => { - console.log('Item clicked:', name) - }, - chainIcon: ChainIcon, - chainName: 'Solana', - relay: 'https://nc2.nightly.app' - } +export const Error: Story = (args: NightlyModalArgs) => { + const [{ timeoutError }, updateArgs] = useArgs() + + if (!args.sessionId) + setTimeout(() => { + updateArgs({ timeoutError: true }) + }, 5000) + + return html`` +} + +Error.args = { + selectorItems: [ + { name: 'Phantom', icon: Phantom, status: 'recent' }, + { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, + { name: 'MetaMask', icon: MetaMask, status: '' }, + { name: 'Glow', icon: Glow, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: 'detected' }, + { name: 'Trust', icon: Trust, status: '' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Sollet', icon: Sollet, status: '' }, + { name: 'Phantom', icon: Phantom, status: '' }, + { name: 'MetaMask', icon: MetaMask, status: 'recent' }, + { name: 'Coinbase', icon: Coinbase, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: '' }, + { name: 'Trust', icon: Trust, status: 'detected' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Phantom', icon: Phantom, status: 'recent' }, + { name: 'Nightly Wallet', icon: NightlyIcon, status: 'recent' }, + { name: 'MetaMask', icon: MetaMask, status: '' }, + { name: 'Glow', icon: Glow, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: 'detected' }, + { name: 'Trust', icon: Trust, status: '' }, + { name: 'Binance', icon: Binance, status: '' }, + { name: 'Sollet', icon: Sollet, status: '' }, + { name: 'Phantom', icon: Phantom, status: '' }, + { name: 'MetaMask', icon: MetaMask, status: 'recent' }, + { name: 'Coinbase', icon: Coinbase, status: '' }, + { name: 'ZenGO', icon: ZenGO, status: '' }, + { name: 'Trust', icon: Trust, status: 'detected' }, + { name: 'Binance', icon: Binance, status: '' } + ], + onWalletClick: (name: string) => { + console.log('Item clicked:', name) + }, + chainIcon: ChainIcon, + chainName: 'Solana', + relay: 'https://nc2.nightly.app' } diff --git a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts index 7f9915d2..551c5e35 100644 --- a/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts +++ b/sdk/packages/modal/src/components/nightly-desktop-main/nightly-desktop-main.ts @@ -32,22 +32,20 @@ export class NightlyDesktopMain extends LitElement { @property({ type: Object }) qrConfigOverride: Partial = {} + @property({ type: Boolean }) + timeoutError = false + @state() copyMessage = 'Copy' @state() qrSource: string | undefined = undefined - @state() - timeoutError: boolean = false - @state() isSessionIdImmediatelyDefined: boolean = false timeoutRef: number | undefined = undefined - loadingTimeout: number | undefined = undefined - onCopy = () => { navigator.clipboard.writeText( 'nc:' + @@ -65,8 +63,7 @@ export class NightlyDesktopMain extends LitElement { } private updateQrSource = () => { - if (this.sessionId) { - clearTimeout(this.loadingTimeout) + if (this.sessionId) this.qrSource = svgToBase64( generateQrCodeXml( 'nc:' + @@ -83,32 +80,15 @@ export class NightlyDesktopMain extends LitElement { } ) ) - } } connectedCallback(): void { super.connectedCallback() - this.loadingTimeout = setTimeout(() => { - if (this.sessionId) clearTimeout(this.loadingTimeout) - // timeout error when sessionId takes longer than 5 seconds to arrive - else { - clearTimeout(this.loadingTimeout) - this.timeoutError = true - } - }, 5000) as unknown as number - this.updateQrSource() - if (this.sessionId) this.isSessionIdImmediatelyDefined = true } - disconnectedCallback(): void { - super.disconnectedCallback() - - clearTimeout(this.loadingTimeout) - } - protected updated(_changedProperties: PropertyValueMap | Map): void { super.updated(_changedProperties) diff --git a/sdk/packages/modal/src/components/nightly-mobile-qr/nightly-mobile-qr.ts b/sdk/packages/modal/src/components/nightly-mobile-qr/nightly-mobile-qr.ts index 757aee50..2bc8bdb9 100644 --- a/sdk/packages/modal/src/components/nightly-mobile-qr/nightly-mobile-qr.ts +++ b/sdk/packages/modal/src/components/nightly-mobile-qr/nightly-mobile-qr.ts @@ -24,21 +24,17 @@ export class NightlyMobileQr extends LitElement { @property({ type: Object }) qrConfigOverride: Partial = {} - @state() - qrSource: string | undefined = undefined + @property({ type: Boolean }) + timeoutError = false @state() - timeoutError: boolean = false + qrSource: string | undefined = undefined @state() isSessionIdImmediatelyDefined: boolean = false - loadingTimeout: number | undefined = undefined - private updateQrSource = () => { - if (this.sessionId) { - clearTimeout(this.loadingTimeout) - + if (this.sessionId) this.qrSource = svgToBase64( generateQrCodeXml( 'nc:' + @@ -55,31 +51,15 @@ export class NightlyMobileQr extends LitElement { } ) ) - } } connectedCallback(): void { super.connectedCallback() - this.loadingTimeout = setTimeout(() => { - if (this.sessionId) clearTimeout(this.loadingTimeout) - // timeout error when sessionId takes longer than 5 seconds to arrive - else { - clearTimeout(this.loadingTimeout) - this.timeoutError = true - } - }, 5000) as unknown as number - this.updateQrSource() if (this.sessionId) this.isSessionIdImmediatelyDefined = true } - disconnectedCallback(): void { - super.disconnectedCallback() - - clearTimeout(this.loadingTimeout) - } - protected updated(_changedProperties: PropertyValueMap | Map): void { super.updated(_changedProperties) diff --git a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts index 46c6fcca..5a5b2fdf 100644 --- a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts +++ b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.stories.ts @@ -150,13 +150,18 @@ let { sessionId: _, ...rest } = Default.args Loading.args = { ...rest } export const Error: Story = (args: NightlyModalArgs) => { - const [{ open }, updateArgs] = useArgs() + const [{ open, timeoutError }, updateArgs] = useArgs() const handleClose = () => { updateArgs({ open: false }) args.onClose() } + if (!args.sessionId) + setTimeout(() => { + updateArgs({ timeoutError: true }) + }, 5000) + return open ? html` { .chainName=${args.chainName} ?connecting=${args.connecting} .relay=${args.relay} + .timeoutError=${timeoutError} > ` : html`` diff --git a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.ts b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.ts index 5c0f9b27..b69fdc42 100644 --- a/sdk/packages/modal/src/components/nightly-selector/nightly-selector.ts +++ b/sdk/packages/modal/src/components/nightly-selector/nightly-selector.ts @@ -47,6 +47,9 @@ export class NightlySelector extends LitElement { @property({ type: Object }) qrConfigOverride: Partial = {} + @property({ type: Boolean }) + timeoutError = false + // state @state() @@ -235,6 +238,7 @@ export class NightlySelector extends LitElement { .sessionId=${this.sessionId} .relay=${this.relay} .qrConfigOverride=${this.qrConfigOverride} + .timeoutError=${this.timeoutError} > ` } @@ -274,6 +278,7 @@ export class NightlySelector extends LitElement { .relay=${this.relay} .showAllWallets=${this.returnToMobileInit} .qrConfigOverride=${this.qrConfigOverride} + .timeoutError=${this.timeoutError} > ` }