Skip to content

Commit

Permalink
feat(app): switching to web3modal (#2669)
Browse files Browse the repository at this point in the history
* feat(app): switching to web3modal - WIP

* working except for buffer injection issue

* fixed buffer issue, minor UX improvements

* feat(app): fixed alignment/spacing of dashboard top components

* fix(app): use default dashboard if customization key is removed from URL

* tweaks

* fix(tests): test fixes

* fix(app): reload when connected address changes
  • Loading branch information
lucianHymer committed Jul 8, 2024
1 parent eff5971 commit 7dc0c42
Show file tree
Hide file tree
Showing 32 changed files with 908 additions and 1,846 deletions.
3 changes: 0 additions & 3 deletions app/__mocks__/@web3-onboard/common.js

This file was deleted.

11 changes: 0 additions & 11 deletions app/__mocks__/@web3-onboard/react.js

This file was deleted.

42 changes: 42 additions & 0 deletions app/__mocks__/web3modalMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
var address = "0xfF7edbD01e9d044486781ff52c42EA7a01612644";
var switchNetwork = jest.fn();
var openModal = jest.fn();

module.exports = {
mockAddress: address,
switchNetworkMock: switchNetwork,
openModalMock: openModal,
useDisconnect: () => ({
disconnect: jest.fn(),
}),
useSwitchNetwork: () => ({
switchNetwork: switchNetwork,
}),
defaultConfig: jest.fn(),
createWeb3Modal: jest.fn(),
useWeb3ModalError: () => ({
error: undefined,
}),
useWeb3ModalProvider: () => ({
provider: jest.fn(),
}),
useWeb3ModalState: () => ({
open: false,
}),
useWeb3Modal: () => ({
open: openModal,
}),
useWeb3ModalEvents: () => ({
data: {
event: "MODAL_CLOSE",
properties: {
connected: true,
},
},
}),
useWeb3ModalAccount: () => ({
isConnected: true,
address: address,
chain: 10,
}),
};
23 changes: 0 additions & 23 deletions app/__test-fixtures__/onboardHookValues.ts

This file was deleted.

20 changes: 4 additions & 16 deletions app/__tests__/components/SyncToChainButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,12 @@ import { makeTestCeramicContext, renderWithContext } from "../../__test-fixtures
import { CeramicContextState } from "../../context/ceramicContext";
import { Chain } from "../../utils/chains";
import { ChakraProvider } from "@chakra-ui/react";

const mockSetChain = jest.fn();

jest.mock("@web3-onboard/react", () => ({
init: () => ({
connectWallet: jest.fn(),
disconnectWallet: () => Promise.resolve(),
state: {
select: () => ({
subscribe: () => {},
}),
},
}),
}));
import { switchNetworkMock } from "../../__mocks__/web3modalMock";

const mockWalletState = {
address: "0x123",
provider: jest.fn(),
chain: "0x14a33",
setChain: mockSetChain,
};

jest.mock("../../context/walletStore", () => ({
Expand Down Expand Up @@ -79,6 +65,8 @@ const chainConfig = {
label: "test",
rpcUrl: "test",
icon: "icon",
chainLink: "",
explorerUrl: "",
};

const chainWithoutEas = new Chain(chainConfig);
Expand Down Expand Up @@ -138,7 +126,7 @@ describe("SyncToChainButton component", () => {
const btn = screen.getByTestId("sync-to-chain-button");
expect(btn).toHaveTextContent("Mint");
fireEvent.click(btn);
await waitFor(() => expect(mockSetChain).toHaveBeenCalled());
await waitFor(() => expect(switchNetworkMock).toHaveBeenCalled());
});
it("should render error toast if no stamps", async () => {
renderWithContext(
Expand Down
3 changes: 1 addition & 2 deletions app/__tests__/context/datastoreConnectionContext.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { render, waitFor, screen, fireEvent } from "@testing-library/react";
import * as framework from "@self.id/framework";
import { EthereumWebAuth } from "@didtools/pkh-ethereum";
import { AccountId } from "caip";
import { useEffect, useState } from "react";
import { mockAddress, mockWallet } from "../../__test-fixtures__/onboardHookValues";
import { makeTestCeramicContext } from "../../__test-fixtures__/contextTestHelpers";

import {
DatastoreConnectionContextProvider,
useDatastoreConnectionContext,
} from "../../context/datastoreConnectionContext";
import { mockAddress } from "../../__mocks__/web3modalMock.js";
import { CeramicContext } from "../../context/ceramicContext";
import { Eip1193Provider } from "ethers";
import { DIDSession } from "did-session";
Expand Down
32 changes: 26 additions & 6 deletions app/__tests__/pages/Home.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Home from "../../pages/Home";
import { HashRouter as Router } from "react-router-dom";
import { makeTestCeramicContext, renderWithContext } from "../../__test-fixtures__/contextTestHelpers";
import { CeramicContextState } from "../../context/ceramicContext";
import { useWeb3ModalAccount, openModalMock } from "../../__mocks__/web3modalMock";

import { checkShowOnboard } from "../../utils/helpers";

Expand Down Expand Up @@ -51,7 +52,10 @@ test("renders connect wallet button", () => {
});

test("clicking connect wallet button calls connect", async () => {
expect.assertions(1);
const oldUseWeb3ModalAccount = useWeb3ModalAccount;
(useWeb3ModalAccount as any) = () => ({
isConnected: false,
});

renderWithContext(
mockCeramicContext,
Expand All @@ -64,30 +68,46 @@ test("clicking connect wallet button calls connect", async () => {
await userEvent.click(connectWalletButton);

await waitFor(() => {
expect(mockConnect).toBeCalledTimes(1);
expect(openModalMock).toBeCalledTimes(1);
});

(useWeb3ModalAccount as any) = oldUseWeb3ModalAccount;
});

describe("Welcome navigation", () => {
it("calls navigate with /dashboard when wallet is connected but checkShowOnboard is false", () => {
it("calls navigate with /dashboard when wallet is connected but checkShowOnboard is false", async () => {
(checkShowOnboard as jest.Mock).mockReturnValue(false);
renderWithContext(
{ ...mockCeramicContext, passport: undefined },
<Router>
<Home />
</Router>
);
expect(navigate).toHaveBeenCalledWith("/dashboard");

const connectWalletButton = screen.getByTestId("connectWalletButton");

await userEvent.click(connectWalletButton);

await waitFor(() => {
expect(navigate).toHaveBeenCalledWith("/dashboard");
});
});

it("calls navigate with /welcome when checkShowOnboard is true", () => {
it("calls navigate with /welcome when checkShowOnboard is true", async () => {
(checkShowOnboard as jest.Mock).mockReturnValue(true);
renderWithContext(
{ ...mockCeramicContext, passport: undefined },
<Router>
<Home />
</Router>
);
expect(navigate).toHaveBeenCalledWith("/welcome");

const connectWalletButton = screen.getByTestId("connectWalletButton");

await userEvent.click(connectWalletButton);

await waitFor(() => {
expect(navigate).toHaveBeenCalledWith("/dashboard");
});
});
});
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
// --- React components/methods
import React, { useEffect } from "react";

import { useAccountCenter } from "@web3-onboard/react";
import React, { useEffect, useState } from "react";

const shouldMinimize = () => {
return window.innerWidth < 640 || window.pageYOffset > 120 || (window.pageYOffset > 50 && window.innerWidth < 1024);
return window.scrollY > 120 || (window.screenY > 50 && window.innerWidth < 1024);
};

const ManageAccountCenter = ({ children }: { children: React.ReactNode }) => {
const updateAccountCenter = useAccountCenter();
const position = "topRight";
export const AccountCenter = () => {
const [minimized, setMinimized] = useState(false);

useEffect(() => {
const onEvent = () => {
if (shouldMinimize()) {
updateAccountCenter({ minimal: true, position });
} else {
updateAccountCenter({ minimal: false, position });
}
setMinimized(shouldMinimize());
};

// run on mount to set initial state
Expand All @@ -38,9 +31,16 @@ const ManageAccountCenter = ({ children }: { children: React.ReactNode }) => {
window.removeEventListener("scroll", onEvent);
window.removeEventListener("resize", onEvent);
};
}, [updateAccountCenter]);

return <>{children}</>;
}, []);

return (
<div className="fixed right-2 md:right-10 lg:right-20 top-3 rounded-2xl w-fit h-fit bg-background z-10 flex justify-end">
<div className="hidden xl:block">
<w3m-button balance={minimized ? "hide" : "show"} size="sm" />
</div>
<div className="xl:hidden block">
<w3m-button balance="hide" size="sm" />
</div>
</div>
);
};

export default ManageAccountCenter;
6 changes: 4 additions & 2 deletions app/components/LoadButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { Spinner } from "./Spinner";

export type LoadingButtonProps = ButtonProps & {
isLoading?: boolean;
loadIconPosition?: "left" | "right";
};

export const LoadButton = ({ isLoading, disabled, children, ...props }: LoadingButtonProps) => {
export const LoadButton = ({ isLoading, disabled, children, loadIconPosition, ...props }: LoadingButtonProps) => {
return (
<Button {...props} disabled={disabled || isLoading}>
{isLoading && <Spinner />}
{isLoading && loadIconPosition !== "right" && <Spinner />}
{children}
{isLoading && loadIconPosition === "right" && <Spinner />}
</Button>
);
};
9 changes: 7 additions & 2 deletions app/components/MinimalHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// --- React methods
import React, { useMemo } from "react";
import { AccountCenter } from "./AccountCenter";

type MinimalHeaderProps = {
className?: string;
Expand All @@ -18,13 +19,17 @@ const MinimalHeader = ({ className }: MinimalHeaderProps): JSX.Element => {
const assets = useMemo(() => getAssets(), []);

return (
<div className={`flex h-16 ${className}`}>
<div className="flex items-center">
<div className={`flex items-center h-16 ${className}`}>
<div className="flex-1 flex items-center">
<img className="" src={assets.gitcoinLogo} alt="Gitcoin Logo" />
<img className="mx-3 md:mx-6" src={assets.logoLine} alt="Logo Line" />
<img className="h-8" src={assets.passportLogo} alt="Passport Logo" />
<div className="ml-3 text-2xl text-color-1">Passport</div>
</div>
{/* This is really just a placeholder div, because AccountCenter uses fixed positioning */}
<div className="flex-1">
<AccountCenter />
</div>
</div>
);
};
Expand Down
23 changes: 13 additions & 10 deletions app/components/SIWEButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from "react";
import { Button, ButtonProps } from "./Button";
import { LoadButton, LoadingButtonProps } from "./LoadButton";

const SIWEButton = (props: ButtonProps & { enableEthBranding: boolean }) => {
const { enableEthBranding, ...rest } = props;
const SIWEButton = (props: LoadingButtonProps & { enableEthBranding: boolean; subtext?: string }) => {
const { enableEthBranding, isLoading, subtext, ...rest } = props;
return (
<Button {...rest} className={(props.className || "") + " rounded-sm"}>
{enableEthBranding && (
<LoadButton {...rest} className={(props.className || "") + " rounded-sm"}>
{enableEthBranding && !isLoading && (
<svg className="my-1" width="19" height="30" viewBox="0 0 19 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.22009 22.4887V30.0001L18.4402 17.0493L9.22009 22.4887Z" fill="#2F3030" />
<path d="M9.22009 11.1099V20.751L18.4402 15.2972L9.22009 11.1099Z" fill="black" />
Expand All @@ -15,11 +15,14 @@ const SIWEButton = (props: ButtonProps & { enableEthBranding: boolean }) => {
<path d="M9.22009 0V11.1098L0 15.2971L9.22009 0Z" fill="#828384" />
</svg>
)}
<span className="hidden group-disabled:inline">Loading...</span>
<span className="inline group-disabled:hidden">
Sign in {enableEthBranding ? "with Ethereum" : "using signature"}
</span>
</Button>
<div className="flex flex-col items-center">
<span className="hidden group-disabled:inline">Logging in...</span>
<span className="inline group-disabled:hidden">
Sign in {enableEthBranding ? "with Ethereum" : "using signature"}
</span>
<div className={`text-xs ${subtext ? "block" : "hidden"}`}>({subtext})</div>
</div>
</LoadButton>
);
};

Expand Down
37 changes: 0 additions & 37 deletions app/config/filters.ts

This file was deleted.

Loading

0 comments on commit 7dc0c42

Please sign in to comment.