Skip to content

Commit

Permalink
Merge pull request #30 from pierobassa/add-wallet-page
Browse files Browse the repository at this point in the history
feat: add connected wallet page, components and utils
  • Loading branch information
akanoce committed Sep 24, 2023
2 parents 6741d99 + 709070c commit 1999ac7
Show file tree
Hide file tree
Showing 14 changed files with 528 additions and 0 deletions.
208 changes: 208 additions & 0 deletions src/components/AccountCard/AccountCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import { ethers } from "ethers";
import { DEFUALT_USER_IMG_PLACEHOLDER } from "@/constants";
import { OpenloginUserInfo } from "@toruslabs/openlogin";
import { FormattingUtils } from "@/utils";
import { BiCopy } from "react-icons/bi";
import { FaEthereum } from "react-icons/fa";
import { useCallback, useMemo } from "react";
import { BaseSeparator, BaseSpacer } from "..";
import { useAccountInfo } from "@/hooks";
import { BsSaveFill, BsSendFill } from "react-icons/bs";
import { IconContext } from "react-icons";
import { useAccountStore } from "@/store";
import { RiEditCircleFill } from "react-icons/ri";
import toast from "react-hot-toast";

type Props = {
userInfo: Partial<OpenloginUserInfo>;
lensProfileImage?: string;
lensHandle?: string;
onProfileImageClick: () => void;
};

export default function AccountCard({
userInfo,
lensProfileImage,
lensHandle,
onProfileImageClick
}: Props) {
const { smartAccountAddress } = useAccountStore();

const { ethBalance, generatedValue } = useAccountInfo(
smartAccountAddress ?? ""
);

const userEthBalance = useMemo(() => {
return FormattingUtils.formatNumberPrecision(
ethers.utils.formatEther(ethBalance ?? 0),
3
);
}, [ethBalance]);

const userGeneratedValue = useMemo(() => {
return ethers.utils.formatEther(generatedValue ?? 0);
}, [generatedValue]);

const userTotalValue = useMemo(() => {
const totalEthValue = ethBalance?.add(generatedValue ?? 0);

return FormattingUtils.formatNumberPrecision(
ethers.utils.formatEther(totalEthValue ?? ethers.BigNumber.from(0)),
5
);
}, [ethBalance, generatedValue]);

const handleCopyAddress = useCallback(() => {
navigator.clipboard.writeText(smartAccountAddress ?? "");

toast.success("Copied address to clipboard");
}, [smartAccountAddress]);

return (
<div className="bg-[#2b2b2b] rounded-md self-center mx-auto max-w-xl">
<div className="px-4 py-3">
{/* Account info */}
<div className="flex flex-row items-center justify-between">
<div className="flex flex-row items-center justify-start">
<div
className="relative cursor-pointer"
onClick={onProfileImageClick}
>
<img
className="h-14 w-14 md:h-20 md:w-20 rounded-full"
src={
lensProfileImage
? lensProfileImage
: userInfo?.profileImage ?? DEFUALT_USER_IMG_PLACEHOLDER
}
alt="user-profile-img"
/>
<IconContext.Provider value={{ size: "22" }}>
<RiEditCircleFill className="absolute bottom-1 right-1 bg-stone-600 rounded-full border border-white" />
</IconContext.Provider>
</div>
<div className="pl-2">
<p className="font-medium text-base">
{lensHandle ?? userInfo?.name}
</p>
<div
className="text-xs md:text-sm flex flex-row items-center cursor-pointer hover:text-stone-300 bg-stone-600 py-0.5 px-2 mt-1 rounded-lg"
onClick={handleCopyAddress}
>
{FormattingUtils.humanAddress(smartAccountAddress ?? "", 4, 6)}
<div className="pl-2">
<BiCopy />
</div>
</div>
</div>
</div>
<div className="bg-[#FF89A9] rounded-md text-[#2b2b2b] text-xs md:text-sm">
<div className="py-1 px-2">
<p className="font-medium">Wallet balance</p>
<div className="py-1 px-2 flex flex-row items-center bg-[#99324E] rounded-md ">
<div className="text-white">
<FaEthereum />
</div>
<div className="pl-1 text-white font-medium">
{userEthBalance} ETH
</div>
</div>
</div>
</div>
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
</div>

<div className="flex flex-row items-center justify-center text-sm">
<div className="bg-[#FF89A9] rounded-md text-[#2b2b2b]">
<div className="py-1 px-2">
<p className="font-medium">Total value</p>
<div className="py-1 px-2 flex flex-row items-center bg-[#99324E] rounded-md ">
<div className="text-white">
<FaEthereum />
</div>
<div className="pl-1 text-white font-medium">
{userTotalValue} ETH
</div>
</div>
</div>
</div>

<BaseSpacer width={24} />

<div className="bg-[#FF89A9] rounded-md text-[#2b2b2b] text-sm">
<div className="py-1 px-2">
<p className="font-medium">Generated value</p>
<div className="py-1 px-2 flex flex-row items-center bg-[#99324E] rounded-md ">
<div className="text-white">
<FaEthereum />
</div>
<div className="pl-1 text-white font-medium">
{userGeneratedValue} ETH
</div>
</div>
</div>
</div>
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
</div>

<div className="flex flex-row items-center justify-center text-sm">
<button className="bg-[#FF89A9] hover:brightness-90 rounded-md text-[#2b2b2b] w-32">
<div className="px-3 flex flex-col items-center justify-center py-3">
<IconContext.Provider value={{ size: "32" }}>
<BsSaveFill />
</IconContext.Provider>

<BaseSpacer height={12} />

<p className="font-medium">Deposit ETH</p>
</div>
</button>

<BaseSpacer width={24} />

<div className="bg-[#FF89A9] hover:brightness-90 rounded-md text-[#2b2b2b] w-32">
<button className="px-3 flex flex-col items-center justify-center py-3 ">
<IconContext.Provider value={{ size: "32" }}>
<BsSendFill />
</IconContext.Provider>

<BaseSpacer height={12} />

<p className="font-medium">Withdraw ETH</p>
</button>
</div>
</div>

<div className="py-6">
<BaseSeparator color="#444444" />
</div>

<div>
<div className="w-full flex items-center justify-center">
<button className="bg-[#FF89A9] hover:brightness-90 rounded-md text-[#2b2b2b] w-[17rem]">
<p className="py-2 px-2 font-medium uppercase text-base">
Export wallet
</p>
</button>
</div>

<BaseSpacer height={12} />

<div className="w-full flex items-center justify-center">
<button className="bg-stone-600 hover:brightness-90 rounded-md text-white w-[17rem]">
<p className="py-2 px-2 font-medium uppercase text-base">
Log out
</p>
</button>
</div>
</div>
</div>
</div>
);
}
1 change: 1 addition & 0 deletions src/components/AccountCard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./AccountCard";
50 changes: 50 additions & 0 deletions src/components/Base/BaseDialog/BaseDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";
import { Dialog, Transition } from "@headlessui/react";
import { Fragment } from "react";

type Props = {
isOpen: boolean;
children: React.ReactNode;
openModal: () => void;
closeModal: () => void;
};

export const BaseDialog = ({ isOpen, children, closeModal }: Props) => {
return (
<>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-black bg-opacity-25" />
</Transition.Child>

<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w-full max-w-md transform overflow-hidden text-left align-middle shadow-xl transition-all">
{children}
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</>
);
};
1 change: 1 addition & 0 deletions src/components/Base/BaseDialog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./BaseDialog";
15 changes: 15 additions & 0 deletions src/components/Base/BaseSeparator/BaseSeparator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type Props = {
color: string;
};

export const BaseSeparator = ({ color }: Props) => {
return (
<div
style={{
backgroundColor: color,
width: "100%",
height: 1
}}
/>
);
};
1 change: 1 addition & 0 deletions src/components/Base/BaseSeparator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./BaseSeparator";
15 changes: 15 additions & 0 deletions src/components/Base/BaseSpacer/BaseSpacer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type Props = {
height?: number;
width?: number;
};

export const BaseSpacer = ({ height = 0, width = 0 }: Props) => {
return (
<div
style={{
height: `${height}px`,
width: `${width}px`
}}
/>
);
};
1 change: 1 addition & 0 deletions src/components/Base/BaseSpacer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./BaseSpacer";
3 changes: 3 additions & 0 deletions src/components/Base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./BaseSeparator";
export * from "./BaseSpacer";
export * from "./BaseDialog";
Loading

0 comments on commit 1999ac7

Please sign in to comment.