Skip to content

Commit

Permalink
ConnectWallet fixes and Improvements (#2303)
Browse files Browse the repository at this point in the history
  • Loading branch information
MananTank authored Feb 13, 2024
1 parent 94a699c commit 9e6b3e5
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 78 deletions.
25 changes: 25 additions & 0 deletions .changeset/lovely-beers-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@thirdweb-dev/react": patch
---

- Fix the closing of ConnectWallet after the wallet connection instead of showing the "Sign In" screen when Auth is enabled

- Call the `onConnect` prop on `ConnectWallet` and `ConnectEmbed` component with the connected wallet instance

```tsx
<ConnectWallet
onConnect={(wallet) => {
console.log("Connected to:", wallet);
}}
/>
```

```tsx
<ConnectEmbed
onConnect={(wallet) => {
console.log("Connected to:", wallet);
}}
/>
```

- Improved Sign in Screen UI for Embedded Wallet and Local Wallet with Retry and Disconnect buttons after failed sign in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Theme } from "../../design-system";
import { WelcomeScreen } from "../../wallet/ConnectWallet/screens/types";
import { useTWLocale } from "./locale-provider";
import { canFitWideModal } from "../utils/canFitWIdeModal";
import { WalletInstance } from "@thirdweb-dev/react-core";

type BoolSetter = (value: boolean) => void;

Expand All @@ -21,7 +22,7 @@ export type ModalConfig = {
onLogout?: () => void;
};
isEmbed?: boolean;
onConnect?: () => void;
onConnect?: (wallet: WalletInstance) => void;
showThirdwebBranding?: boolean;
};

Expand Down Expand Up @@ -56,7 +57,7 @@ export const WalletUIStatesProvider = (
onLogin?: (token: string) => void;
onLogout?: () => void;
};
onConnect?: () => void;
onConnect?: (wallet: WalletInstance) => void;
showThirdwebBranding?: boolean;
}>,
) => {
Expand Down
9 changes: 5 additions & 4 deletions packages/react/src/wallet/ConnectWallet/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Theme, iconSize } from "../../design-system";
import { ConnectedWalletDetails } from "./Details";
import {
WalletInstance,
useAddress,
useConnectionStatus,
useLogout,
Expand Down Expand Up @@ -313,12 +314,12 @@ export type ConnectWalletProps = {
hideDisconnect?: boolean;

/**
* Callback to be called on successful connection of wallet
* Callback to be called on successful connection of wallet. The connected wallet instance is passed as an argument to the callback
*
* ```tsx
* <ConnectWallet
* onConnect={() => {
* console.log("wallet connected")
* onConnect={(wallet) => {
* console.log("connected to", wallet)
* }}
* />
* ```
Expand All @@ -336,7 +337,7 @@ export type ConnectWalletProps = {
* ```
*
*/
onConnect?: () => void;
onConnect?: (wallet: WalletInstance) => void;

/**
* Render custom UI at the bottom of the ConnectWallet Details Modal
Expand Down
12 changes: 6 additions & 6 deletions packages/react/src/wallet/ConnectWallet/Modal/ConnectEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useTWLocale } from "../../../evm/providers/locale-provider";
import { StyledDiv } from "../../../design-system/elements";
import { Theme, radius } from "../../../design-system";
import {
WalletInstance,
useConnectionStatus,
useThirdwebAuthContext,
useUser,
Expand Down Expand Up @@ -93,12 +94,12 @@ export type ConnectEmbedProps = {
};

/**
* Callback to be called on successful connection of wallet
* Callback to be called on successful connection of wallet. The callback is called with the connected wallet instance as the first argument
*
* ```tsx
* <ConnectEmbed
* onConnect={() => {
* console.log("wallet connected")
* onConnect={(wallet) => {
* console.log("connected to", wallet)
* }}
* />
* ```
Expand All @@ -116,7 +117,7 @@ export type ConnectEmbedProps = {
* ```
*
*/
onConnect?: () => void;
onConnect?: (wallet: WalletInstance) => void;

/**
* By default, A "Powered by Thirdweb" branding is shown at the bottom of the embed.
Expand Down Expand Up @@ -330,8 +331,7 @@ export function ConnectEmbed(props: ConnectEmbedProps) {
}

const ConnectEmbedContent = (
props: Omit<ConnectEmbedProps, "onConnect"> & {
onConnect?: () => void;
props: ConnectEmbedProps & {
loginOptional?: boolean;
},
) => {
Expand Down
87 changes: 44 additions & 43 deletions packages/react/src/wallet/ConnectWallet/Modal/ConnectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Modal } from "../../../components/Modal";
import { WalletSelector } from "../WalletSelector";
import {
WalletConfig,
WalletInstance,
useAddress,
useConnect,
useConnectionStatus,
Expand Down Expand Up @@ -61,37 +62,42 @@ export const ConnectModalContent = (props: {
const { user } = useUser();
const authConfig = useThirdwebAuthContext();

const handleConnected = useCallback(() => {
if (onConnect) {
onConnect();
}
const [handleConnectedPending, setIsHandleConnectedPending] = useState(false);

const requiresSignIn = modalConfig.auth?.loginOptional
? false
: !!authConfig?.authUrl && !user?.address;
const handleConnected = useCallback(
(_wallet: WalletInstance) => {
if (onConnect) {
onConnect(_wallet);
}

onModalUnmount(() => {
onShow();
});
const requiresSignIn = modalConfig.auth?.loginOptional
? false
: !!authConfig?.authUrl && !user?.address;

// show sign in screen if required
if (requiresSignIn) {
setScreen(reservedScreens.signIn);
}
onModalUnmount(() => {
onShow();
});

// close modal and reset screen
else {
onClose();
}
}, [
modalConfig.auth?.loginOptional,
authConfig?.authUrl,
user?.address,
setScreen,
onShow,
onClose,
onConnect,
]);
// show sign in screen if required
if (requiresSignIn) {
setScreen(reservedScreens.signIn);
}

// close modal and reset screen
else {
onClose();
}
},
[
modalConfig.auth?.loginOptional,
authConfig?.authUrl,
user?.address,
setScreen,
onShow,
onClose,
onConnect,
],
);

const handleBack = useCallback(() => {
setScreen(initialScreen);
Expand All @@ -110,6 +116,14 @@ export const ConnectModalContent = (props: {
activeWallet,
} = useWalletContext();

// wait for the wallet state to be updated before calling handleConnected
useEffect(() => {
if (activeWallet && handleConnectedPending) {
handleConnected(activeWallet);
setIsHandleConnectedPending(false);
}
}, [handleConnectedPending, activeWallet, handleConnected]);

const walletList = (
<WalletSelector
title={title}
Expand Down Expand Up @@ -138,7 +152,9 @@ export const ConnectModalContent = (props: {
supportedWallets={walletConfigs}
theme={typeof theme === "string" ? theme : theme.type}
goBack={handleBack}
connected={handleConnected}
connected={() => {
setIsHandleConnectedPending(true);
}}
isOpen={props.isOpen}
show={onShow}
hide={onHide}
Expand Down Expand Up @@ -271,21 +287,6 @@ export const ConnectModal = () => {
const onHide = useCallback(() => setHideModal(true), []);
const onShow = useCallback(() => setHideModal(false), []);

// if wallet is suddenly disconnected when showing the sign in screen, close the modal and reset the screen
useEffect(() => {
if (isWalletModalOpen && screen === reservedScreens.signIn && !wallet) {
setScreen(initialScreen);
setIsWalletModalOpen(false);
}
}, [
initialScreen,
isWalletModalOpen,
screen,
setIsWalletModalOpen,
setScreen,
wallet,
]);

return (
<CustomThemeProvider theme={theme}>
<Modal
Expand Down
70 changes: 47 additions & 23 deletions packages/react/src/wallet/ConnectWallet/SignatureScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ import { ModalConfigCtx } from "../../evm/providers/wallet-ui-states-provider";
import { wait } from "../../utils/wait";
import { Button } from "../../components/buttons";
import { iconSize, radius, spacing } from "../../design-system";
import {
CrossCircledIcon,
ExternalLinkIcon,
ReloadIcon,
} from "@radix-ui/react-icons";
import { ExternalLinkIcon, ReloadIcon } from "@radix-ui/react-icons";
import { Img } from "../../components/Img";
import { walletIds } from "@thirdweb-dev/wallets";
import { safeChainIdToSlug } from "../wallets/safe/safeChainSlug";
Expand All @@ -46,7 +42,6 @@ export const SignatureScreen: React.FC<{
const { auth } = useContext(ModalConfigCtx);
const [status, setStatus] = useState<Status>("idle");
const { login } = useLogin();
const [tryId, setTryId] = useState(0);
const disconnect = useDisconnect();

const isSafeWallet = wallet?.walletId === walletIds.safe;
Expand Down Expand Up @@ -81,6 +76,7 @@ export const SignatureScreen: React.FC<{
style={{
minHeight: "300px",
}}
fullHeight
>
<Spinner size="xl" color="accentText" />
</Container>
Expand All @@ -93,7 +89,6 @@ export const SignatureScreen: React.FC<{

const handleRetry = () => {
signIn();
setTryId(tryId + 1);
};

return (
Expand Down Expand Up @@ -166,7 +161,6 @@ export const SignatureScreen: React.FC<{
{walletConfig && (
<Container py="3xl">
<WalletLogoSpinner
key={String(tryId)}
error={status === "failed"}
iconUrl={walletConfig.meta.iconURL}
/>
Expand Down Expand Up @@ -294,8 +288,9 @@ function HeadlessSignIn({
signIn: () => void;
status: Status;
}) {
const locale = useTWLocale().connectWallet.signatureScreen.signingScreen;
const locale = useTWLocale().connectWallet.signatureScreen;
const mounted = useRef(false);
const disconnect = useDisconnect();
useEffect(() => {
if (mounted.current) {
return;
Expand All @@ -306,7 +301,7 @@ function HeadlessSignIn({

return (
<Container p="lg" fullHeight flex="column" animate="fadein">
<ModalHeader title={locale.title} />
<ModalHeader title={locale.signingScreen.title} />
<Container
expand
flex="row"
Expand All @@ -315,19 +310,48 @@ function HeadlessSignIn({
minHeight: "250px",
}}
>
{status === "failed" ? (
<Container
flex="column"
gap="lg"
color="danger"
center="both"
animate="fadein"
>
<CrossCircledIcon width={iconSize.xl} height={iconSize.xl} />
<Text color="danger"> {locale.failedToSignIn} </Text>
</Container>
) : (
<Spinner size="xl" color="accentText" />
{status === "signing" && <Spinner size="xl" color="accentText" />}

{status === "failed" && (
<>
<Container>
<Spacer y="lg" />
<Text size="lg" center color="danger">
{locale.signingScreen.failedToSignIn}
</Text>

<Spacer y="lg" />
<Button
fullWidth
variant="accent"
onClick={() => {
signIn();
}}
style={{
gap: spacing.xs,
alignItems: "center",
padding: spacing.md,
}}
>
<ReloadIcon width={iconSize.sm} height={iconSize.sm} />
{locale.signingScreen.tryAgain}
</Button>
<Spacer y="sm" />
<Button
fullWidth
variant="secondary"
onClick={() => {
disconnect();
}}
style={{
alignItems: "center",
padding: spacing.md,
}}
>
{locale.instructionScreen.disconnectWallet}
</Button>
</Container>
</>
)}
</Container>
</Container>
Expand Down

0 comments on commit 9e6b3e5

Please sign in to comment.