Skip to content

Commit

Permalink
Winston/add embedded wallet export for react (#1622)
Browse files Browse the repository at this point in the history
Co-authored-by: Manan Tank <[email protected]>
  • Loading branch information
ElasticBottle and MananTank authored Sep 19, 2023
1 parent 710739c commit 4268775
Show file tree
Hide file tree
Showing 14 changed files with 749 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-camels-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@thirdweb-dev/react": minor
---

feat(react): add `embeddedWallet` wallet type
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { useSmartWallet } from "./evm/hooks/wallets/useSmartWallet";
export { bloctoWallet } from "./wallet/wallets/blocto/bloctoWallet";
export { coinbaseWallet } from "./wallet/wallets/coinbase/coinbaseWallet";
export { embeddedWallet } from "./wallet/wallets/embeddedWallet/embeddedWallet";
export { frameWallet } from "./wallet/wallets/frame/frameWallet";
export { localWallet } from "./wallet/wallets/localWallet/localWallet";
export { magicLink } from "./wallet/wallets/magic/magicLink";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import styled from "@emotion/styled";
import { Spacer } from "../../../components/Spacer";
import { Container, ModalHeader } from "../../../components/basic";
import { Button } from "../../../components/buttons";
import { Theme, iconSize, spacing } from "../../../design-system";
import { GoogleIcon } from "../../ConnectWallet/icons/GoogleIcon";
import { InputSelectionUI } from "../InputSelectionUI";
import type { EmbeddedWalletLoginType } from "./types";
import {
WalletConfig,
useCreateWalletInstance,
useSetConnectedWallet,
useSetConnectionStatus,
} from "@thirdweb-dev/react-core";
import { EmbeddedWallet } from "@thirdweb-dev/wallets";

export const EmbeddedWalletFormUI = (props: {
onSelect: (loginType: EmbeddedWalletLoginType) => void;
showOrSeparator?: boolean;
walletConfig: WalletConfig<EmbeddedWallet>;
}) => {
const createWalletInstance = useCreateWalletInstance();
const setConnectionStatus = useSetConnectionStatus();
const setConnectedWallet = useSetConnectedWallet();

// Need to trigger google login on button click to avoid popup from being blocked
const googleLogin = async () => {
try {
const embeddedWallet = createWalletInstance(props.walletConfig);
setConnectionStatus("connecting");
await embeddedWallet.connect({ googleLogin: true });
setConnectedWallet(embeddedWallet);
close();
} catch (e) {
setConnectionStatus("disconnected");
console.error(e);
}
};

return (
<div>
<SocialButton
variant="secondary"
fullWidth
onClick={() => {
googleLogin();
props.onSelect({ google: true });
}}
>
<GoogleIcon size={iconSize.md} />
Sign in with Google
</SocialButton>

<Spacer y="lg" />

<InputSelectionUI
onSelect={(email) => props.onSelect({ email })}
placeholder="Enter your email address"
name="email"
type="email"
errorMessage={(_input) => {
const input = _input.replace(/\+/g, "");
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
const isValidEmail = emailRegex.test(input);
if (!isValidEmail) {
return "Invalid email address";
}
}}
emptyErrorMessage="email address is required"
showOrSeparator={props.showOrSeparator}
/>
</div>
);
};

export const EmbeddedWalletFormUIScreen: React.FC<{
onSelect: (loginType: EmbeddedWalletLoginType) => void;
onBack: () => void;
modalSize: "compact" | "wide";
walletConfig: WalletConfig<EmbeddedWallet>;
}> = (props) => {
const isCompact = props.modalSize === "compact";
return (
<Container
fullHeight
flex="column"
p="lg"
animate="fadein"
style={{
minHeight: "250px",
}}
>
<ModalHeader onBack={props.onBack} title="Sign in" />
{isCompact ? <Spacer y="xl" /> : null}

<Container
expand
flex="column"
center="y"
p={isCompact ? undefined : "lg"}
>
<EmbeddedWalletFormUI
walletConfig={props.walletConfig}
onSelect={props.onSelect}
showOrSeparator={false}
/>
</Container>
</Container>
);
};

const SocialButton = /* @__PURE__ */ styled(Button)<{ theme?: Theme }>`
display: flex;
justify-content: center;
gap: ${spacing.sm};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
ConnectUIProps,
useConnectionStatus,
useCreateWalletInstance,
useSetConnectedWallet,
useSetConnectionStatus,
} from "@thirdweb-dev/react-core";
import { EmbeddedWallet } from "@thirdweb-dev/wallets";
import { Spacer } from "../../../components/Spacer";
import { Spinner } from "../../../components/Spinner";
import { Container, ModalHeader } from "../../../components/basic";
import { Button } from "../../../components/buttons";
import { ModalTitle } from "../../../components/modalElements";
import { Text } from "../../../components/text";
import { iconSize } from "../../../design-system";
import { GoogleIcon } from "../../ConnectWallet/icons/GoogleIcon";

export const EmbeddedWalletGoogleLogin = (
props: ConnectUIProps<EmbeddedWallet>,
) => {
const { goBack, modalSize } = props;
const createWalletInstance = useCreateWalletInstance();
const setConnectionStatus = useSetConnectionStatus();
const setConnectedWallet = useSetConnectedWallet();
const connectionStatus = useConnectionStatus();

const googleLogin = async () => {
try {
const embeddedWallet = createWalletInstance(props.walletConfig);
setConnectionStatus("connecting");
await embeddedWallet.connect({ googleLogin: true });
setConnectedWallet(embeddedWallet);
props.close();
} catch (e) {
setConnectionStatus("disconnected");
console.error(e);
}
};

return (
<Container animate="fadein" flex="column" fullHeight>
<Container
flex="column"
expand
p="lg"
style={{
paddingBottom: 0,
}}
>
<ModalHeader
title={
<Container flex="row" center="both" gap="xs">
<GoogleIcon size={iconSize.md} />
<ModalTitle> Sign in </ModalTitle>
</Container>
}
onBack={goBack}
/>

{modalSize === "compact" ? <Spacer y="xl" /> : null}

<Container
flex="column"
center="both"
expand
style={{
textAlign: "center",
minHeight: "250px",
}}
>
{connectionStatus === "connecting" && (
<Container animate="fadein">
<Text
color="primaryText"
multiline
style={{
maxWidth: "250px",
}}
>
Select your Google account in the pop-up
</Text>
<Spacer y="xl" />
<Container center="x" flex="row">
<Spinner size="lg" color="accentText" />
</Container>

<Spacer y="xxl" />
</Container>
)}

{connectionStatus === "disconnected" && (
<Container animate="fadein">
<Text color="danger">Failed to sign in</Text>
<Spacer y="lg" />
<Button variant="primary" onClick={googleLogin}>
{" "}
Retry{" "}
</Button>
<Spacer y="xxl" />
</Container>
)}
</Container>
</Container>
</Container>
);
};
Loading

0 comments on commit 4268775

Please sign in to comment.