diff --git a/.changeset/five-pumas-wash.md b/.changeset/five-pumas-wash.md new file mode 100644 index 00000000..53d402a0 --- /dev/null +++ b/.changeset/five-pumas-wash.md @@ -0,0 +1,18 @@ +--- +'@reown/appkit-scaffold-react-native': patch +'@reown/appkit-ethers5-react-native': patch +'@reown/appkit-ethers-react-native': patch +'@reown/appkit-wagmi-react-native': patch +'@reown/appkit-core-react-native': patch +'@reown/appkit-auth-ethers-react-native': patch +'@reown/appkit-auth-wagmi-react-native': patch +'@reown/appkit-coinbase-ethers-react-native': patch +'@reown/appkit-coinbase-wagmi-react-native': patch +'@reown/appkit-common-react-native': patch +'@reown/appkit-scaffold-utils-react-native': patch +'@reown/appkit-siwe-react-native': patch +'@reown/appkit-ui-react-native': patch +'@reown/appkit-wallet-react-native': patch +--- + +chore: added event subscription hook diff --git a/.changeset/proud-badgers-provide.md b/.changeset/proud-badgers-provide.md new file mode 100644 index 00000000..b6d2b315 --- /dev/null +++ b/.changeset/proud-badgers-provide.md @@ -0,0 +1,18 @@ +--- +'@reown/appkit-wagmi-react-native': patch +'@reown/appkit-auth-ethers-react-native': patch +'@reown/appkit-auth-wagmi-react-native': patch +'@reown/appkit-coinbase-ethers-react-native': patch +'@reown/appkit-coinbase-wagmi-react-native': patch +'@reown/appkit-common-react-native': patch +'@reown/appkit-core-react-native': patch +'@reown/appkit-ethers-react-native': patch +'@reown/appkit-ethers5-react-native': patch +'@reown/appkit-scaffold-react-native': patch +'@reown/appkit-scaffold-utils-react-native': patch +'@reown/appkit-siwe-react-native': patch +'@reown/appkit-ui-react-native': patch +'@reown/appkit-wallet-react-native': patch +--- + +fix: changed condition for initial modal loading diff --git a/packages/core/src/controllers/EventsController.ts b/packages/core/src/controllers/EventsController.ts index 48e45cb1..339229ec 100644 --- a/packages/core/src/controllers/EventsController.ts +++ b/packages/core/src/controllers/EventsController.ts @@ -3,7 +3,7 @@ import { ApiController } from './ApiController'; import { OptionsController } from './OptionsController'; import { CoreHelperUtil } from '../utils/CoreHelperUtil'; import { FetchUtil } from '../utils/FetchUtil'; -import type { Event } from '../utils/TypeUtil'; +import type { Event, EventName } from '../utils/TypeUtil'; // -- Helpers ------------------------------------------- // const baseUrl = CoreHelperUtil.getAnalyticsUrl(); @@ -33,6 +33,14 @@ export const EventsController = { return sub(state, () => callback(state)); }, + subscribeEvent(event: EventName, callback: (newEvent: EventsControllerState) => void) { + return sub(state, () => { + if (state.data.event === event) { + callback(state); + } + }); + }, + async _sendAnalyticsEvent(data: EventsControllerState['data'], timestamp: number) { if (excluded.includes(data.event)) { return; diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts index 41c6e626..498a1810 100644 --- a/packages/core/src/utils/TypeUtil.ts +++ b/packages/core/src/utils/TypeUtil.ts @@ -343,6 +343,51 @@ export type CustomWallet = Pick< >; // -- EventsController Types ---------------------------------------------------- +export type EventName = + | 'MODAL_LOADED' + | 'MODAL_OPEN' + | 'MODAL_CLOSE' + | 'CLICK_ALL_WALLETS' + | 'CLICK_NETWORKS' + | 'SWITCH_NETWORK' + | 'SELECT_WALLET' + | 'CONNECT_SUCCESS' + | 'CONNECT_ERROR' + | 'DISCONNECT_SUCCESS' + | 'DISCONNECT_ERROR' + | 'CLICK_WALLET_HELP' + | 'CLICK_NETWORK_HELP' + | 'CLICK_GET_WALLET' + | 'EMAIL_LOGIN_SELECTED' + | 'EMAIL_SUBMITTED' + | 'DEVICE_REGISTERED_FOR_EMAIL' + | 'EMAIL_VERIFICATION_CODE_SENT' + | 'EMAIL_VERIFICATION_CODE_PASS' + | 'EMAIL_VERIFICATION_CODE_FAIL' + | 'EMAIL_EDIT' + | 'EMAIL_EDIT_COMPLETE' + | 'EMAIL_UPGRADE_FROM_MODAL' + | 'CLICK_SIGN_SIWE_MESSAGE' + | 'CLICK_CANCEL_SIWE' + | 'SIWE_AUTH_SUCCESS' + | 'SIWE_AUTH_ERROR' + | 'CLICK_TRANSACTIONS' + | 'ERROR_FETCH_TRANSACTIONS' + | 'LOAD_MORE_TRANSACTIONS' + | 'OPEN_SEND' + | 'OPEN_SWAP' + | 'INITIATE_SWAP' + | 'SWAP_SUCCESS' + | 'SWAP_ERROR' + | 'SEND_INITIATED' + | 'SEND_SUCCESS' + | 'SEND_ERROR' + | 'SOCIAL_LOGIN_STARTED' + | 'SOCIAL_LOGIN_SUCCESS' + | 'SOCIAL_LOGIN_REQUEST_USER_DATA' + | 'SOCIAL_LOGIN_CANCELED' + | 'SOCIAL_LOGIN_ERROR' + | 'SET_PREFERRED_ACCOUNT_TYPE'; export type Event = | { diff --git a/packages/ethers/src/index.tsx b/packages/ethers/src/index.tsx index 19a6dcbf..ccdeddbf 100644 --- a/packages/ethers/src/index.tsx +++ b/packages/ethers/src/index.tsx @@ -13,6 +13,7 @@ export { NetworkButton, AppKit } from '@reown/appkit-scaffold-react-native'; +import type { EventName, EventsControllerState } from '@reown/appkit-scaffold-react-native'; export { defaultConfig } from './utils/defaultConfig'; @@ -129,7 +130,7 @@ export function useAppKitError() { }; } -export function useAppKitEvents() { +export function useAppKitEvents(callback?: (newEvent: EventsControllerState) => void) { if (!modal) { throw new Error('Please call "createAppKit" before using "useAppKitEvents" hook'); } @@ -139,12 +140,30 @@ export function useAppKitEvents() { useEffect(() => { const unsubscribe = modal?.subscribeEvents(newEvent => { setEvents({ ...newEvent }); + callback?.(newEvent); }); return () => { unsubscribe?.(); }; - }, []); + }, [callback]); return event; } + +export function useAppKitEventSubscription( + event: EventName, + callback: (newEvent: EventsControllerState) => void +) { + if (!modal) { + throw new Error('Please call "createAppKit" before using "useAppKitEventSubscription" hook'); + } + + useEffect(() => { + const unsubscribe = modal?.subscribeEvent(event, callback); + + return () => { + unsubscribe?.(); + }; + }, [callback, event]); +} diff --git a/packages/ethers5/src/index.tsx b/packages/ethers5/src/index.tsx index c213a748..72e55c58 100644 --- a/packages/ethers5/src/index.tsx +++ b/packages/ethers5/src/index.tsx @@ -6,6 +6,7 @@ export { NetworkButton, AppKit } from '@reown/appkit-scaffold-react-native'; +import type { EventName, EventsControllerState } from '@reown/appkit-scaffold-react-native'; import { ConstantsUtil, EthersStoreUtil, @@ -126,7 +127,7 @@ export function useAppKitError() { }; } -export function useAppKitEvents() { +export function useAppKitEvents(callback?: (newEvent: EventsControllerState) => void) { if (!modal) { throw new Error('Please call "createAppKit" before using "useAppKitEvents" hook'); } @@ -136,12 +137,30 @@ export function useAppKitEvents() { useEffect(() => { const unsubscribe = modal?.subscribeEvents(newEvent => { setEvents({ ...newEvent }); + callback?.(newEvent); }); return () => { unsubscribe?.(); }; - }, []); + }, [callback]); return event; } + +export function useAppKitEventSubscription( + event: EventName, + callback: (newEvent: EventsControllerState) => void +) { + if (!modal) { + throw new Error('Please call "createAppKit" before using "useAppKitEventSubscription" hook'); + } + + useEffect(() => { + const unsubscribe = modal?.subscribeEvent(event, callback); + + return () => { + unsubscribe?.(); + }; + }, [callback, event]); +} diff --git a/packages/scaffold/src/client.ts b/packages/scaffold/src/client.ts index a5a3fc9e..60daf796 100644 --- a/packages/scaffold/src/client.ts +++ b/packages/scaffold/src/client.ts @@ -12,7 +12,8 @@ import type { ThemeControllerState, Connector, ConnectedWalletInfo, - Features + Features, + EventName } from '@reown/appkit-core-react-native'; import { SIWEController, type SIWEControllerClient } from '@reown/appkit-siwe-react-native'; import { @@ -145,6 +146,10 @@ export class AppKitScaffold { return EventsController.subscribe(callback); } + public subscribeEvent(event: EventName, callback: (newEvent: EventsControllerState) => void) { + return EventsController.subscribeEvent(event, callback); + } + public resolveReownName = async (name: string) => { const wcNameAddress = await EnsController.resolveName(name); const networkNameAddresses = wcNameAddress?.addresses diff --git a/packages/wagmi/src/client.ts b/packages/wagmi/src/client.ts index 828f0471..15e2b5c6 100644 --- a/packages/wagmi/src/client.ts +++ b/packages/wagmi/src/client.ts @@ -377,8 +377,12 @@ export class AppKit extends AppKitScaffold { }); watchAccount(wagmiConfig, { - onChange: accountData => { + onChange: (accountData, prevAccountData) => { this.syncAccount({ ...accountData }); + + if (accountData.status === 'disconnected' && prevAccountData.status === 'connected') { + this.close(); + } } }); } @@ -431,7 +435,7 @@ export class AppKit extends AppKitScaffold { 'address' | 'isConnected' | 'chainId' | 'connector' | 'isConnecting' | 'isReconnecting' >) { this.syncNetwork(address, chainId, isConnected); - this.setLoading(isConnecting || isReconnecting); + this.setLoading(!!connector && (isConnecting || isReconnecting)); if (isConnected && address && chainId) { const caipAddress: CaipAddress = `${ConstantsUtil.EIP155}:${chainId}:${address}`; @@ -444,8 +448,7 @@ export class AppKit extends AppKitScaffold { this.getApprovedCaipNetworksData() ]); this.hasSyncedConnectedAccount = true; - } else if (!isConnected && this.hasSyncedConnectedAccount) { - this.close(); + } else if (!isConnected && !isConnecting && !isReconnecting && this.hasSyncedConnectedAccount) { this.resetAccount(); this.resetWcConnection(); this.resetNetwork(); @@ -619,7 +622,6 @@ export class AppKit extends AppKitScaffold { provider.onSetPreferredAccount(async () => { await reconnect(this.wagmiConfig, { connectors: [connector] }); - this.setLoading(false); }); provider.setOnTimeout(async () => { diff --git a/packages/wagmi/src/index.tsx b/packages/wagmi/src/index.tsx index da1d90ad..642fe8e4 100644 --- a/packages/wagmi/src/index.tsx +++ b/packages/wagmi/src/index.tsx @@ -6,6 +6,7 @@ export { NetworkButton, AppKit } from '@reown/appkit-scaffold-react-native'; +import type { EventName, EventsControllerState } from '@reown/appkit-scaffold-react-native'; import { ConstantsUtil } from '@reown/appkit-scaffold-utils-react-native'; export { defaultWagmiConfig } from './utils/defaultWagmiConfig'; import { useEffect, useState, useSyncExternalStore } from 'react'; @@ -82,7 +83,7 @@ export function useWalletInfo() { return { walletInfo }; } -export function useAppKitEvents() { +export function useAppKitEvents(callback?: (newEvent: EventsControllerState) => void) { if (!modal) { throw new Error('Please call "createAppKit" before using "useAppKitEvents" hook'); } @@ -92,12 +93,30 @@ export function useAppKitEvents() { useEffect(() => { const unsubscribe = modal?.subscribeEvents(newEvent => { setEvents({ ...newEvent }); + callback?.(newEvent); }); return () => { unsubscribe?.(); }; - }, []); + }, [callback]); return event; } + +export function useAppKitEventSubscription( + event: EventName, + callback: (newEvent: EventsControllerState) => void +) { + if (!modal) { + throw new Error('Please call "createAppKit" before using "useAppKitEventSubscription" hook'); + } + + useEffect(() => { + const unsubscribe = modal?.subscribeEvent(event, callback); + + return () => { + unsubscribe?.(); + }; + }, [callback, event]); +}