From c1a641fb5cc34f84d97535006d698efd3e563036 Mon Sep 17 00:00:00 2001 From: Enes Date: Thu, 12 Dec 2024 12:44:08 +0300 Subject: [PATCH] refactor: filter out the duplicate wallets when there is both injected and recent (#3446) --- .changeset/warm-ligers-flow.md | 23 ++++ .../w3m-connect-recent-widget/index.ts | 29 ++++- .../src/views/w3m-connecting-wc-view/index.ts | 1 + .../w3m-connect-recent-widget.test.ts | 120 ++++++++++++++++++ 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 .changeset/warm-ligers-flow.md create mode 100644 packages/scaffold-ui/test/partials/w3m-connect-recent-widget.test.ts diff --git a/.changeset/warm-ligers-flow.md b/.changeset/warm-ligers-flow.md new file mode 100644 index 0000000000..914cfdafce --- /dev/null +++ b/.changeset/warm-ligers-flow.md @@ -0,0 +1,23 @@ +--- +'@reown/appkit-scaffold-ui': patch +'@apps/builder': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit': patch +'@reown/appkit-utils': patch +'@reown/appkit-cdn': patch +'@reown/appkit-cli': patch +'@reown/appkit-common': patch +'@reown/appkit-core': patch +'@reown/appkit-experimental': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-siwe': patch +'@reown/appkit-siwx': patch +'@reown/appkit-ui': patch +'@reown/appkit-wallet': patch +'@reown/appkit-wallet-button': patch +--- + +Filter out when there is duplicate wallet items in recents and injected wallets diff --git a/packages/scaffold-ui/src/partials/w3m-connect-recent-widget/index.ts b/packages/scaffold-ui/src/partials/w3m-connect-recent-widget/index.ts index 65173644ef..10638c2683 100644 --- a/packages/scaffold-ui/src/partials/w3m-connect-recent-widget/index.ts +++ b/packages/scaffold-ui/src/partials/w3m-connect-recent-widget/index.ts @@ -1,20 +1,39 @@ import type { WcWallet } from '@reown/appkit-core' -import { AssetUtil, RouterController, StorageUtil } from '@reown/appkit-core' +import { AssetUtil, ConnectorController, RouterController, StorageUtil } from '@reown/appkit-core' import { customElement } from '@reown/appkit-ui' import { LitElement, html } from 'lit' -import { property } from 'lit/decorators.js' +import { property, state } from 'lit/decorators.js' import { ifDefined } from 'lit/directives/if-defined.js' @customElement('w3m-connect-recent-widget') export class W3mConnectRecentWidget extends LitElement { + // -- Members ------------------------------------------- // + private unsubscribe: (() => void)[] = [] + // -- State & Properties -------------------------------- // @property() public tabIdx?: number = undefined + @state() private connectors = ConnectorController.state.connectors + + // -- Lifecycle ----------------------------------------- // + public constructor() { + super() + this.unsubscribe.push( + ConnectorController.subscribeKey('connectors', val => (this.connectors = val)) + ) + } + // -- Render -------------------------------------------- // public override render() { - const recent = StorageUtil.getRecentWallets() + const recentWallets = StorageUtil.getRecentWallets() + const filteredRecentWallets = recentWallets.filter( + wallet => + !this.connectors.some( + connector => connector.id === wallet.id || connector.name === wallet.name + ) + ) - if (!recent?.length) { + if (!filteredRecentWallets.length) { this.style.cssText = `display: none` return null @@ -22,7 +41,7 @@ export class W3mConnectRecentWidget extends LitElement { return html` - ${recent.map( + ${filteredRecentWallets.map( wallet => html` { + const mockRecentWallets = [ + { id: 'recent1', name: 'Recent Wallet 1' }, + { id: 'recent2', name: 'Recent Wallet 2' } + ] + + const mockConnectors = [ + { id: 'connector1', name: 'Connector 1' }, + { id: 'recent1', name: 'Recent Wallet 1' } // Matching wallet + ] + + let subscribeCallback: (connectors: any) => void + + beforeEach(() => { + subscribeCallback = vi.fn() + + vi.spyOn(StorageUtil, 'getRecentWallets').mockReturnValue(mockRecentWallets) + + vi.spyOn(ConnectorController, 'state', 'get').mockReturnValue({ + connectors: mockConnectors + } as any) + + vi.spyOn(ConnectorController, 'subscribeKey').mockImplementation((_, callback) => { + subscribeCallback = callback + return () => undefined + }) + }) + + afterEach(() => { + vi.clearAllMocks() + }) + + it('should render filtered recent wallets when there are matching connectors', async () => { + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + const walletElements = element.shadowRoot?.querySelectorAll('wui-list-wallet') + expect(walletElements?.length).toBe(1) + + const walletName = walletElements?.[0]?.getAttribute('name') + expect(walletName).toBe('Recent Wallet 2') + }) + + it('should render all recent wallets when there are no matching connectors', async () => { + vi.spyOn(ConnectorController, 'state', 'get').mockReturnValue({ + connectors: [{ id: 'connector1', name: 'Connector 1' }] + } as any) + + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + const walletElements = element.shadowRoot?.querySelectorAll('wui-list-wallet') + expect(walletElements?.length).toBe(2) + + const walletNames = Array.from(walletElements || []).map(el => el.getAttribute('name')) + expect(walletNames).toContain('Recent Wallet 1') + expect(walletNames).toContain('Recent Wallet 2') + }) + + it('should not render widget when there are no recent wallets', async () => { + vi.spyOn(StorageUtil, 'getRecentWallets').mockReturnValue([]) + + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + expect(element.style.display).toBe('none') + expect(element.shadowRoot?.querySelector('wui-flex')).toBeNull() + }) + + it('should handle wallet click and navigate to connecting view', async () => { + const routerSpy = vi.spyOn(RouterController, 'push') + + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + const walletElement = element.shadowRoot?.querySelector('wui-list-wallet') + walletElement?.click() + + expect(routerSpy).toHaveBeenCalledWith('ConnectingWalletConnect', { + wallet: mockRecentWallets[1] + }) + }) + + it('should respect tabIdx property', async () => { + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + const walletElement = element.shadowRoot?.querySelector('wui-list-wallet') + expect(walletElement?.getAttribute('tabIdx')).toBe('2') + }) + + it('should update when connectors change', async () => { + const element: W3mConnectRecentWidget = await fixture( + html`` + ) + + expect(element.shadowRoot?.querySelectorAll('wui-list-wallet').length).toBe(1) + + vi.spyOn(ConnectorController, 'state', 'get').mockReturnValue({ + connectors: [{ id: 'connector1', name: 'Connector 1' }] + } as any) + + subscribeCallback([{ id: 'connector1', name: 'Connector 1' }]) + + await element.updateComplete + + expect(element.shadowRoot?.querySelectorAll('wui-list-wallet').length).toBe(2) + }) +})