Skip to content

Commit

Permalink
Merge pull request #12 from DevNode-Dev/feat/connect-wallet-create-did
Browse files Browse the repository at this point in the history
Added did gen on wallet connect
  • Loading branch information
rushidhanwant authored Mar 10, 2023
2 parents fe3e224 + afdd0ad commit 352174f
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import {useWeb3Modal} from '@web3modal/react';
import {useState} from 'react';
import {useAccount, useDisconnect} from 'wagmi';
import * as utils from "../../../utils";
import {EthereumWebAuth, getAccountId} from "@didtools/pkh-ethereum";
import {DIDSession} from "did-session";
import {config} from "../../../config";
import {toast} from "react-toastify";
import useLocalStorage from "../../../hooks/useLocalStorage";

export const ConnectWalletButton = () => {
const {open} = useWeb3Modal()
const {disconnect} = useDisconnect()
const {isConnected, address} = useAccount()
const [loading, setLoading] = useState(false)
const [, setDid] = useLocalStorage("did", "");
const [, setDidSession] = useLocalStorage("didSession", "");

const generateDidSession = async (address: string) => {
const accountId = await getAccountId(window.ethereum, address);
const authMethod = await EthereumWebAuth.getAuthMethod(
window.ethereum,
accountId
);
const session = await DIDSession.authorize(authMethod, {
resources: [`ceramic://*`],
expiresInSecs: config.didSession.expiresInSecs,
});
setDidSession(session.serialize());
setDid(session.did.id);
};

const {address, isConnected} = useAccount({
onConnect(context) {
if (!context.isReconnected) {
generateDidSession(context.address)
.catch(() => {
toast.error("Error initiating did session!")
});
}
},
onDisconnect() {
setDidSession(undefined);
setDid(undefined);
}
});

const onOpen = async () => {
setLoading(true)
Expand All @@ -19,15 +55,19 @@ export const ConnectWalletButton = () => {
}

const getAddress = () => {
return address ? address.slice(0, 8).concat("...") : "";
return address ? utils.formatWalletAddress(address) : "";
}

return (
<button
className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
className={utils.classNames(
"flex h-[48px] items-center justify-center",
"rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-8 py-3 hover:border-[#08010D] focus:outline-none",
"font-medium text-[#97929B] hover:text-[#08010D]",
)}
onClick={onClick}
disabled={loading}>
{ isConnected ? getAddress() : "Connect Wallet"}
{isConnected ? getAddress() : "Connect Wallet"}
</button>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {fireEvent, render, screen} from "@testing-library/react";
import {PrimaryButton} from "./PrimaryButton";

describe("<PrimaryButton />", () => {
it("should render the button with no issues", () => {
const result = render(<PrimaryButton title={"button"} onClick={jest.fn} />);
expect(result.container).toBeInTheDocument();
expect(screen.getByRole("button")).not.toBeDisabled();
});

it("should be disabled if the props has disabled=true", () => {
render(<PrimaryButton title={"button"} disabled={true} onClick={jest.fn} />);
const button = screen.getByRole("button");
expect(button).toBeTruthy();
expect(button).toBeDisabled();
});

it("should handle click event", () => {
const onClick = jest.fn();
render(<PrimaryButton title={"button"} onClick={onClick} />);
fireEvent.click(screen.getByRole("button"));
expect(onClick).toBeCalled();
});

it("should handle custom class names", () => {
const custom = "my-custom-class";
render(<PrimaryButton title={"button"} onClick={jest.fn} classes={custom} />);
expect(screen.getByRole("button")).toHaveClass(custom);
});
});
15 changes: 15 additions & 0 deletions apps/web/src/components/Button/PrimaryButton/PrimaryButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {ButtonProps} from "../types";

export const PrimaryButton = (props: ButtonProps) => {
return (
<button
type="button"
id="primary-button"
className={`cursor-pointer rounded-[10px] h-[48px] bg-[#08010D] px-8 py-3 text-sm font-medium text-white hover:bg-gray-800 ${props.classes || ''}`}
disabled={props.disabled}
onClick={props.onClick}
>
{props.title}
</button>
)
}
1 change: 1 addition & 0 deletions apps/web/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./ConnectWallet/ConnectWalletButton";
export * from "./AccentButton/AccentButton";
export * from "./PrimaryButton/PrimaryButton";
147 changes: 9 additions & 138 deletions apps/web/src/components/NavBar/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
import { Popover, Transition } from "@headlessui/react";
import { Popover } from "@headlessui/react";
import { useAccount } from "wagmi";
import Image from "next/image";
import {Fragment, useEffect, useState} from "react";
import { EthereumWebAuth, getAccountId } from "@didtools/pkh-ethereum";
import { DIDSession } from "did-session";
import useLocalStorage from "../../hooks/useLocalStorage";
import {useEffect} from "react";
import { trpc } from "../../utils/trpc";
import {Modal} from "../Modal";
import Link from "next/link";
import {getDiscordAuthUrl} from "../../config";
import {useRouter} from "next/router";
import {toast} from "react-toastify";
import {ConnectWalletButton} from "../Button";
import {ConnectWalletButton, PrimaryButton} from "../Button";
import * as utils from "../../utils";

const navigation = [{ name: "Ask a question", href: "#", current: true }];

const NavBar = (props) => {
const router = useRouter();
const code = router.query.code as string;
const [did, setDid] = useLocalStorage("did", "");
const [didSession, setDidSession] = useLocalStorage("didSession", "");
const [isOpen, setOpen] = useState(false);
const { address, isConnected } = useAccount();
const { address } = useAccount();

const authorPlatformDetails = trpc.public.getAuthorDiscord.useQuery({
address: address,
});
const discordUserName = authorPlatformDetails.data?.platformUsername ;

discordUserName && props.handleDiscordUser(true);

useEffect(() => {
Expand All @@ -38,41 +29,6 @@ const NavBar = (props) => {
}
}, [code]);

const handleDIDSession = async () => {
if (!isConnected) return;

const accountId = await getAccountId(window.ethereum, address);
const authMethod = await EthereumWebAuth.getAuthMethod(
window.ethereum,
accountId
);

const oneHundredWeeks = 60 * 60 * 24 * 7 * 100;
const session = await DIDSession.authorize(authMethod, {
resources: [`ceramic://*`],
expiresInSecs: oneHundredWeeks,
});

// fetch(
// `/api/user/didSession?&did=${
// session.did.id
// }&didSession=${session.serialize()}&didpkh=did:pkh:eip155:1:${address}`
// );

setDidSession(session.serialize());
props.handleDidSession(true);
setDid(session.did.id);
};

const handleClick = () => {
setOpen((state) => !state);
};

const handleDiscordConnect = () => {
const redirect = getDiscordAuthUrl();
window.location.replace(redirect);
}

const handleDiscordAuthCallback = async (code: string) => {
const response = await fetch(`/api/user/discord-auth/profile?code=${code}`);
const profile = await response.json();
Expand All @@ -96,8 +52,8 @@ const NavBar = (props) => {
{({ open }) => (
<>
<div className="mx-auto h-[100px] max-w-7xl bg-white px-5 lg:px-0">
<div className="flex h-full items-center gap-[34px] lg:gap-[50px]">
<div className="flex min-w-0 grow items-center justify-center gap-[30px] lg:max-w-[75%]">
<div className="flex h-full items-center justify-between gap-[34px] lg:gap-[50px]">
<div className="flex min-w-0 grow items-center gap-[30px] lg:max-w-[75%]">
<Link href="/">
<Image
width="44"
Expand All @@ -108,7 +64,7 @@ const NavBar = (props) => {
/>
</Link>

<div className="flex grow items-center lg:mx-0 lg:max-w-none xl:px-0">
<div className="flex items-center lg:w-[80%] lg:mx-0 lg:max-w-none xl:px-0">
<div className="w-full">
<label htmlFor="search" className="sr-only">
Search
Expand Down Expand Up @@ -141,94 +97,9 @@ const NavBar = (props) => {
</div>
</div>
</div>
<div className="flex items-center lg:hidden">
{/* Mobile menu button */}
{/* <Popover.Button className="-mx-2 inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-black">
<span className="sr-only">Open menu</span>
{open ? (
<XIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<MenuIcon className="block h-6 w-6" aria-hidden="true" />
)}
</Popover.Button> */}
</div>
<div className="hidden gap-[16px] lg:flex lg:w-[40%] lg:items-center lg:justify-start">
<div className="hidden gap-[16px] lg:flex lg:w-max lg:items-end lg:justify-end">
<PrimaryButton title={"Ask a question"} onClick={() => {}} />
<ConnectWalletButton />

{isConnected && did.length > 0 ? (
<Popover className="relative">
<Popover.Button
onClick={async () => {
await navigator.clipboard.writeText(did);
}}
className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
>
{did.slice(8, 12) +
"..." +
did.slice(did.length - 4, did.length)}
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute left-1/2 z-10 mt-3 w-max -translate-x-1/2 transform">
<div className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
<p>DID copied to clipboard!</p>
</div>
</Popover.Panel>
</Transition>
</Popover>
) : (
<button
onClick={() => {
handleDIDSession();
}}
className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
>
Create DID
</button>
)}

{discordUserName ? (
<Popover className="relative">
<Popover.Button
onClick={async () => {
await navigator.clipboard.writeText(did);
}}
className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
>
{discordUserName}
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute left-1/2 z-10 mt-3 w-max -translate-x-1/2 transform">
<div className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
<p>Discord user name copied to clipboard!</p>
</div>
</Popover.Panel>
</Transition>
</Popover>
) : (
<button
onClick={handleDiscordConnect}
className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
>
Connect with Discord bot
</button>
)}
{isOpen && <Modal handleClick={handleClick} />}
</div>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ export const config = {
},
walletConnect: {
projectId: process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID || "",
}
},
didSession: {
expiresInSecs: 60 * 60 * 24 * 7 * 100, // 100 weeks
},
}

export const getDiscordAuthUrl = (): string => {
Expand Down

0 comments on commit 352174f

Please sign in to comment.