Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

feat: add wallet on header and create two pages, assets and create wallet #162

Merged
merged 14 commits into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 6 additions & 13 deletions packages/app/src/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { RequireWallet } from "./components/RequireWallet";
import { MainLayout } from "./layouts/MainLayout";
import { Pages } from "./types/pages";

const AssetsPage = lazy(() => import("~/pages/AssetsPage"));
const SwapPage = lazy(() => import("~/pages/SwapPage"));
const WalletPage = lazy(() => import("~/pages/WalletPage"));
const CreateWallet = lazy(() => import("~/pages/CreateWallet"));
const MintTokenPage = lazy(() => import("~/pages/MintTokenPage"));
const FaucetPage = lazy(() => import("~/pages/FaucetPage"));
const PoolPage = lazy(() => import("~/pages/PoolPage/index"));
const AddLiquidity = lazy(() => import("./pages/PoolPage/AddLiquidity"));
const RemoveLiquidityPage = lazy(
Expand All @@ -23,15 +23,16 @@ export default function AppRoutes() {
path="*"
element={
<RequireWallet>
<Navigate to={Pages.wallet} />
<Navigate to="/swap" />
pedronauck marked this conversation as resolved.
Show resolved Hide resolved
</RequireWallet>
}
/>
<Route path={Pages.createWallet} element={<CreateWallet />} />
<Route
path={Pages.wallet}
path={Pages.assets}
element={
<RequireWallet>
<WalletPage />
<AssetsPage />
</RequireWallet>
}
/>
Expand Down Expand Up @@ -70,14 +71,6 @@ export default function AppRoutes() {
</RequireWallet>
}
/>
<Route
pedronauck marked this conversation as resolved.
Show resolved Hide resolved
path={Pages.faucet}
element={
<RequireWallet>
<FaucetPage />
</RequireWallet>
}
/>
</Route>
</Routes>
);
Expand Down
51 changes: 42 additions & 9 deletions packages/app/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { FocusScope, useFocusManager } from "@react-aria/focus";
import cx from "classnames";
import clipboard from "clipboard";
import type { ComponentType, ReactNode } from "react";
import { BiWallet, BiDollarCircle } from "react-icons/bi";
import { MdSwapCalls } from "react-icons/md";
import toast from "react-hot-toast";
import { BiDollarCircle } from "react-icons/bi";
import { FaRegCopy } from "react-icons/fa";
import { MdChecklist, MdSwapCalls } from "react-icons/md";
import { useLocation, useNavigate } from "react-router-dom";

import { Button } from "./Button";

import fuelLogo from "~/assets/fuel-logo-512x512.png";
import { useWallet } from "~/context/AppContext";
import { useEthBalance } from "~/hooks/useEthBalance";
import { Pages } from "~/types/pages";

const style = {
Expand All @@ -22,6 +26,8 @@ const style = {
button: `flex items-center bg-gray-800 rounded-2xl mx-2 font-semi-bold`,
buttonPadding: `p-2`,
navIcon: `text-gray-500 stroke-current`,
wallet: `flex items-center gap-3 absolute top-4 right-4 rounded-full
text-gray-300 bg-gray-800 inner-shadow p-1`,
};

const HeaderNav = ({
Expand Down Expand Up @@ -70,6 +76,12 @@ const Header = () => {
const wallet = useWallet();
const navigate = useNavigate();
const location = useLocation();
const ethBalance = useEthBalance();

const handleCopy = () => {
clipboard.copy(wallet!.address);
toast("Address copied", { icon: "✨" });
};

return (
<div className={style.wrapper}>
Expand All @@ -80,13 +92,6 @@ const Header = () => {
<div className={style.nav}>
<FocusScope>
<div className={style.navItemsContainer}>
<HeaderNav
icon={BiWallet}
onPress={() => navigate(Pages.wallet)}
isActive={location.pathname === Pages.wallet}
>
Wallet
</HeaderNav>
<HeaderNav
icon={MdSwapCalls}
onPress={() => navigate(Pages.swap)}
Expand All @@ -101,10 +106,38 @@ const Header = () => {
>
Pool
</HeaderNav>
<HeaderNav
icon={MdChecklist}
onPress={() => navigate(Pages.assets)}
isActive={location.pathname.includes(Pages.assets)}
>
Assets
</HeaderNav>
</div>
</FocusScope>
</div>
)}
{wallet && (
<nav
className={cx(style.wallet, {
"pl-5": Boolean(ethBalance.formatted),
})}
>
<>
{ethBalance.formatted && <span>{ethBalance.formatted} ETH</span>}
<Button
aria-label="Copy your wallet address"
onPress={handleCopy}
className="bg-gray-700 px-4 rounded-full"
>
<span className="text-gray-100">
{wallet?.address.slice(0, 4)}...{wallet?.address.slice(-4)}
</span>
<FaRegCopy size="1em" />
</Button>
</>
</nav>
)}
</div>
);
};
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/components/PageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export const PageContent: PageContentComponent = ({ className, children }) => {
);
return (
<div className={style.wrapper}>
<div className={cx(className, style.content)}>
<div className={cx(className, style.content, { "py-8": !title })}>
{title}
<div className={cx(style.divider, "my-3")} />
{title && <div className={cx(style.divider, "my-3")} />}
<div className="px-5 pb-2">{customChildren}</div>
</div>
</div>
Expand Down
8 changes: 3 additions & 5 deletions packages/app/src/components/RequireWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Navigate, useLocation, useResolvedPath } from "react-router-dom";
import { Navigate } from "react-router-dom";

import { useWallet } from "~/context/AppContext";
import { Pages } from "~/types/pages";

export const RequireWallet = ({ children }: { children: JSX.Element }) => {
const wallet = useWallet();
const location = useLocation();
const path = useResolvedPath(location.pathname);

if (!wallet && path.pathname !== "/wallet") {
return <Navigate to={Pages.wallet} replace={true} />;
if (!wallet) {
return <Navigate to={Pages.createWallet} replace={true} />;
}

return children;
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/hooks/useBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import { useWallet } from '~/context/AppContext';

export function useBalances(opts: UseQueryOptions = {}) {
const wallet = useWallet();
return useQuery('AssetsPage-balances', () => wallet!.getBalances(), opts as any);
return useQuery('AssetsPage-balances', () => wallet?.getBalances(), opts as any);
}
17 changes: 17 additions & 0 deletions packages/app/src/hooks/useEthBalance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { formatUnits } from 'ethers/lib/utils';

import { useBalances } from './useBalances';

import { DECIMAL_UNITS } from '~/config';
import CoinsMetadata from '~/lib/CoinsMetadata';

const ETH_ID = CoinsMetadata.find((item) => item.symbol === 'ETH')?.assetId;

export function useEthBalance() {
const { data: balances } = useBalances();
const balance = balances?.find((item) => item.assetId === ETH_ID)?.amount;
return {
raw: balance,
formatted: balance && formatUnits(balance, DECIMAL_UNITS),
};
}
3 changes: 3 additions & 0 deletions packages/app/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,7 @@ body,
.coin-selector[aria-disabled="true"] {
@apply opacity-100;
}
.inner-shadow {
box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.2);
}
}
38 changes: 22 additions & 16 deletions packages/app/src/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { useQueryErrorResetBoundary } from "react-query";
import { Outlet } from "react-router-dom";
import { Outlet, useLocation, useResolvedPath } from "react-router-dom";

import Header from "~/components/Header";

Expand All @@ -14,6 +14,8 @@ const style = {

export function MainLayout() {
const { reset: resetReactQuery } = useQueryErrorResetBoundary();
const location = useLocation();
const path = useResolvedPath(location);

return (
<div className={style.wrapper}>
Expand Down Expand Up @@ -45,22 +47,26 @@ export function MainLayout() {
</div>
)}
>
<Suspense
fallback={
<div
style={{
display: "flex",
flex: 1,
placeItems: "center",
placeContent: "center",
}}
>
<div style={{ textAlign: "center" }}>Loading...</div>
</div>
}
>
{path.pathname === "/create-wallet" ? (
pedronauck marked this conversation as resolved.
Show resolved Hide resolved
<Outlet />
</Suspense>
) : (
<Suspense
fallback={
<div
style={{
display: "flex",
flex: 1,
placeItems: "center",
placeContent: "center",
}}
>
<div style={{ textAlign: "center" }}>Loading...</div>
</div>
}
>
<Outlet />
</Suspense>
)}
</ErrorBoundary>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,58 +1,52 @@
import clipboard from "clipboard";
import type { ReactNode } from "react";
import toast from "react-hot-toast";
import { BiCoin, BiDotsHorizontalRounded, BiWallet } from "react-icons/bi";
import { FaFaucet, FaRegCopy } from "react-icons/fa";
import { Link, useNavigate } from "react-router-dom";

import { Menu } from "./Menu";
import { PageContent } from "./PageContent";
import { Popover, usePopover } from "./Popover";
import { BiCoin, BiDotsHorizontalRounded } from "react-icons/bi";
import { FaFaucet } from "react-icons/fa";
import { MdChecklist } from "react-icons/md";
import { useNavigate, Link as RouterLink } from "react-router-dom";

import { AssetItem } from "~/components/AssetItem";
import { Button } from "~/components/Button";
import { Link } from "~/components/Link";
import { Menu } from "~/components/Menu";
import { PageContent } from "~/components/PageContent";
import { Popover, usePopover } from "~/components/Popover";
import { Spinner } from "~/components/Spinner";
import { ENABLE_FAUCET_API } from "~/config";
import { useWallet } from "~/context/AppContext";
import { useAssets } from "~/hooks/useAssets";
import { useFaucet } from "~/hooks/useFaucet";
import { Pages } from "~/types/pages";

export type WalletPropsCard = {
children: ReactNode;
onFaucetAdded?: () => void;
};

export function WalletCard({ children, onFaucetAdded }: WalletPropsCard) {
export default function AssetsPage() {
const wallet = useWallet();
const navigate = useNavigate();
const popover = usePopover({ placement: "bottom" });
const { coins, isLoading, refetch } = useAssets();

const faucetMutation = useFaucet({
const faucet = useFaucet({
onSuccess: () => {
toast.success("Faucet added successfully!");
onFaucetAdded?.();
refetch();
},
});

const handleCopy = () => {
clipboard.copy(wallet!.address);
toast("Address copied", { icon: "✨" });
};

function handleFaucet() {
faucetMutation.mutate();
faucet.mutate();
popover.close();
}

const titleElementRight = wallet && (
<div className="flex items-center gap-3">
{ENABLE_FAUCET_API ? (
<Link to={Pages.faucet}>
<RouterLink to={Pages.faucet}>
<FaFaucet />
</Link>
</RouterLink>
) : (
<>
<Button
autoFocus
variant="ghost"
isLoading={faucetMutation.isLoading}
isLoading={faucet.isLoading}
{...popover.getTriggerProps()}
>
<BiDotsHorizontalRounded size="1.2rem" />
Expand All @@ -78,19 +72,28 @@ export function WalletCard({ children, onFaucetAdded }: WalletPropsCard) {
<PageContent>
<PageContent.Title elementRight={titleElementRight}>
<div className="flex items-center gap-2 mr-2">
<BiWallet className="text-primary-500" />
Wallet
<MdChecklist className="text-primary-500" />
Assets
</div>
{wallet && (
<Button aria-label="Copy your wallet address" onPress={handleCopy}>
<span className="text-gray-100">
{wallet?.address.slice(0, 4)}...{wallet?.address.slice(-4)}
</span>
<FaRegCopy size="1em" />
</Button>
)}
</PageContent.Title>
{children}
{isLoading && (
<div className="flex justify-start rounded-xl px-2 pt-2">
<Spinner />
</div>
)}
{coins.map((coin) => (
<div className="mt-4" key={coin.assetId}>
<AssetItem key={coin.assetId} coin={coin} />
</div>
))}
{!isLoading && !coins.length && (
<div className="text-gray-300 pb-1">
There&apos; no asset added yet.
<br />
<Link onPress={() => faucet.mutate()}>Click here</Link> to generate a
new asset.
</div>
)}
</PageContent>
);
}
Loading