Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add onConnect handler to <ConnectWallet /> #1529

Merged
merged 50 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5e172e7
docs - add missing prop to doc
Oct 24, 2024
8087864
docs
Oct 24, 2024
1ba10f2
revert
Oct 24, 2024
482acb2
save
Oct 24, 2024
f6622fb
fixes
Oct 24, 2024
7ddd0fe
Merge branch 'dms/playground-fixes' into dms/wallet-proto-1
Oct 24, 2024
6ee2629
remove
Oct 24, 2024
e84bff3
remove arb class name
Oct 24, 2024
a3f3cf2
Merge branch 'dms/playground-fixes' into dms/wallet-proto-1
Oct 24, 2024
0dddd5e
prototype
Oct 24, 2024
f6514e2
hm
Oct 25, 2024
1deb207
save
Oct 25, 2024
8830380
prototyping
Oct 28, 2024
87dc933
proto
Oct 28, 2024
db75d31
Merge branch 'main' into dms/wallet-proto-1
Oct 28, 2024
07fc53d
clean
Oct 28, 2024
2c7fbea
cleaning
Oct 28, 2024
ba687b1
cleaning deps
Oct 28, 2024
1d01215
fix
Oct 28, 2024
78ca04d
testing
Oct 28, 2024
84c221e
add tests
Oct 28, 2024
a1c6eca
remove console.log
Oct 28, 2024
a7eb783
clean up comments
Oct 28, 2024
169682c
format
Oct 28, 2024
a44e5a9
fixes
Oct 29, 2024
be2ebba
pnpm
Oct 29, 2024
140ac2d
remove rainbow
Oct 29, 2024
3c4cc2c
make more robust
Oct 29, 2024
3549d07
rewrite tests
Oct 29, 2024
11497f4
remove rainbow
Oct 29, 2024
05b585b
follow conventions for useState and useEffect
Oct 29, 2024
d0720f6
reverts
Oct 29, 2024
69227f8
revert
Oct 29, 2024
c1890e8
package reset
Oct 29, 2024
b0a4c98
format
Oct 29, 2024
af8c06d
remove pnpm
Oct 29, 2024
492d0ea
clean
Oct 29, 2024
c45afcb
format
Oct 29, 2024
cfadac0
reset bun lock
Oct 30, 2024
bdb8b0f
reset
Oct 30, 2024
06dd7b4
reset
Oct 30, 2024
3686242
reset yarn
Oct 30, 2024
330831a
standardize comments
Oct 30, 2024
1f87f10
test
Oct 30, 2024
6440e1e
reset
Oct 30, 2024
3f073a3
cleanup
Oct 30, 2024
209e63a
changeset
Oct 30, 2024
9969089
update
Oct 30, 2024
8d7cdac
typos
Oct 30, 2024
2b84a2e
chore:rename to onConnect
Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/good-beans-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@coinbase/onchainkit': minor
---

feat: add `onInitialConnect` handler to `<ConnectWallet />`. By @dschlabach #1529
120 changes: 111 additions & 9 deletions src/wallet/components/ConnectWallet.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe('ConnectWallet', () => {
expect(connectedText).toBeInTheDocument();
});

it('should calls connect function when connect button is clicked', () => {
it('should call connect function when connect button is clicked', () => {
const connectMock = vi.fn();
vi.mocked(useConnect).mockReturnValue({
connectors: [{ id: 'mockConnector' }],
Expand All @@ -98,9 +98,14 @@ describe('ConnectWallet', () => {
render(<ConnectWallet text="Connect Wallet" />);
const button = screen.getByTestId('ockConnectButton');
fireEvent.click(button);
expect(connectMock).toHaveBeenCalledWith({
connector: { id: 'mockConnector' },
});
expect(connectMock).toHaveBeenCalledWith(
{
connector: { id: 'mockConnector' },
},
{
onSuccess: expect.any(Function),
},
);
});

it('should toggle wallet modal on button click when connected', () => {
Expand Down Expand Up @@ -162,6 +167,71 @@ describe('ConnectWallet', () => {
expect(screen.queryByText('Not Render')).not.toBeInTheDocument();
});

it('should call onInitialConnect callback when connect button is clicked', async () => {
const mockUseAccount = vi.mocked(useAccount);
const connectMock = vi.fn();
const onInitialConnectMock = vi.fn();

// Initial state: disconnected
mockUseAccount.mockReturnValue({
address: undefined,
status: 'disconnected',
});

vi.mocked(useConnect).mockReturnValue({
connectors: [{ id: 'mockConnector' }],
connect: connectMock,
status: 'idle',
});

render(
<ConnectWallet
text="Connect Wallet"
onInitialConnect={onInitialConnectMock}
/>,
);

const button = screen.getByTestId('ockConnectButton');
fireEvent.click(button);

// Simulate successful connection
connectMock.mock.calls[0][1].onSuccess();

// Update account status to connected
mockUseAccount.mockReturnValue({
address: '0x123',
status: 'connected',
});

// Force a re-render to trigger the useEffect
render(
<ConnectWallet
text="Connect Wallet"
onInitialConnect={onInitialConnectMock}
/>,
);

expect(onInitialConnectMock).toHaveBeenCalledTimes(1);
});

it('should not call onConnect callback when component is first mounted', () => {
dschlabach marked this conversation as resolved.
Show resolved Hide resolved
const mockUseAccount = vi.mocked(useAccount);
mockUseAccount.mockReturnValue({
address: '0x123',
status: 'connected',
});

const onInitialConnectMock = vi.fn();
render(
<ConnectWallet
text="Connect Wallet"
onInitialConnect={onInitialConnectMock}
/>,
);

expect(onInitialConnectMock).toHaveBeenCalledTimes(0);
});

describe('withWalletAggregator', () => {
beforeEach(() => {
vi.mocked(useAccount).mockReturnValue({
Expand All @@ -175,7 +245,7 @@ describe('ConnectWallet', () => {
});
});

it('should render ConnectButtonRainboKit when withWalletAggregator is true', () => {
it('should render ConnectButtonRainbowKit when withWalletAggregator is true', () => {
render(
<ConnectWallet text="Connect Wallet" withWalletAggregator={true} />,
);
Expand All @@ -198,12 +268,17 @@ describe('ConnectWallet', () => {
);
const connectButton = screen.getByTestId('ockConnectButton');
fireEvent.click(connectButton);
expect(connectMock).toHaveBeenCalledWith({
connector: { id: 'mockConnector' },
});
expect(connectMock).toHaveBeenCalledWith(
{
connector: { id: 'mockConnector' },
},
{
onSuccess: expect.any(Function),
},
);
});

it('should calls openConnectModal function when connect button is clicked', () => {
it('should call openConnectModal function when connect button is clicked', () => {
vi.mocked(useWalletContext).mockReturnValue({
isOpen: false,
setIsOpen: vi.fn(),
Expand All @@ -215,5 +290,32 @@ describe('ConnectWallet', () => {
fireEvent.click(button);
expect(openConnectModalMock).toHaveBeenCalled();
});

it('should call onConnect callback when connect button is clicked', () => {
dschlabach marked this conversation as resolved.
Show resolved Hide resolved
const mockUseAccount = vi.mocked(useAccount);
mockUseAccount.mockReturnValue({
address: undefined,
status: 'disconnected',
});

const onInitialConnectMock = vi.fn();
render(
<ConnectWallet
text="Connect Wallet"
onInitialConnect={onInitialConnectMock}
withWalletAggregator={true}
/>,
);
const button = screen.getByTestId('ockConnectButton');

mockUseAccount.mockReturnValue({
address: '0x123',
status: 'connected',
});

fireEvent.click(button);

expect(onInitialConnectMock).toHaveBeenCalledTimes(1);
});
});
});
29 changes: 27 additions & 2 deletions src/wallet/components/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ConnectButton as ConnectButtonRainbowKit } from '@rainbow-me/rainbowkit';
import { Children, isValidElement, useCallback, useMemo } from 'react';
import type { ReactNode } from 'react';
import { useEffect, useState } from 'react';
import { useAccount, useConnect } from 'wagmi';
import { IdentityProvider } from '../../identity/components/IdentityProvider';
import { Spinner } from '../../internal/components/Spinner';
Expand All @@ -24,12 +25,16 @@ export function ConnectWallet({
// but for now we will keep it for backward compatibility.
text = 'Connect Wallet',
withWalletAggregator = false,
onInitialConnect,
}: ConnectWalletReact) {
// Core Hooks
const { isOpen, setIsOpen } = useWalletContext();
const { address: accountAddress, status } = useAccount();
const { connectors, connect, status: connectStatus } = useConnect();

// State
const [hasClickedConnect, setHasClickedConnect] = useState(false);

// Get connectWalletText from children when present,
// this is used to customize the connect wallet button text
const { connectWalletText } = useMemo(() => {
Expand Down Expand Up @@ -58,6 +63,14 @@ export function ConnectWallet({
setIsOpen(!isOpen);
}, [isOpen, setIsOpen]);

// Effects
useEffect(() => {
if (hasClickedConnect && status === 'connected' && onInitialConnect) {
onInitialConnect();
setHasClickedConnect(false);
}
}, [status, hasClickedConnect, onInitialConnect]);

if (status === 'disconnected') {
if (withWalletAggregator) {
return (
Expand All @@ -67,7 +80,10 @@ export function ConnectWallet({
<ConnectButton
className={className}
connectWalletText={connectWalletText}
onClick={() => openConnectModal()}
onClick={() => {
openConnectModal();
setHasClickedConnect(true);
}}
text={text}
/>
</div>
Expand All @@ -80,7 +96,16 @@ export function ConnectWallet({
<ConnectButton
className={className}
connectWalletText={connectWalletText}
onClick={() => connect({ connector })}
onClick={() => {
connect(
{ connector },
{
onSuccess: () => {
onInitialConnect?.();
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safer, more reliable way of triggering the callback. We have to use the useEffect and state for RainbowKit support

},
);
}}
text={text}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/wallet/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type ConnectWalletReact = {
/** @deprecated Prefer `ConnectWalletText component` */
text?: string; // Optional text override for button
withWalletAggregator?: boolean; // Optional flag to enable the wallet aggregator like RainbowKit
onInitialConnect?: () => void; // Optional callback function to execute when the wallet is connected.
};

/**
Expand Down