Skip to content

Commit

Permalink
feat: As a user, I want to be able to connect my wallet to Explorer a…
Browse files Browse the repository at this point in the history
…nd see the list of my attestations (#456)

Co-authored-by: Taras Oliynyk <taras.oliynyk@hapi.one>
Co-authored-by: Solniechniy <oleksndrkorn@gmail.com>
  • Loading branch information
3 people committed Dec 8, 2023
1 parent d9507b8 commit 46439e2
Show file tree
Hide file tree
Showing 23 changed files with 849 additions and 228 deletions.
3 changes: 2 additions & 1 deletion explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"prettier": "^3.1.0",
"tailwindcss": "^3.3.5",
"typescript": "^5.2.2",
"vite": "^4.5.1"
"vite": "^4.5.1",
"vite-plugin-svgr": "^4.2.0"
}
}
13 changes: 13 additions & 0 deletions explorer/src/components/Buttons/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IButtonsProps } from "./interface";

export const ButtonOutlined: React.FC<IButtonsProps> = ({ name, handler, disabled = false }) => {
return (
<button
onClick={handler}
disabled={disabled}
className="h-12 px-4 py-3 rounded-md border border-button-outlined-border justify-center items-center gap-2 inline-flex text-button-outlined-text text-base font-semibold hover:border-button-outlined-borderHover disabled:opacity-40"
>
{name}
</button>
);
};
5 changes: 5 additions & 0 deletions explorer/src/components/Buttons/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IButtonsProps {
name: string;
handler(): void;
disabled?: boolean;
}
12 changes: 6 additions & 6 deletions explorer/src/components/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import hapi from "@/assets/logo/hapi.svg";
import verax from "@/assets/logo/verax.svg";
import HapiLogo from "@/assets/logo/hapi.svg?react";
import VeraxLogo from "@/assets/logo/verax.svg?react";
import { Link } from "@/components/Link";
import { INFO_LIST } from "@/constants/components";
import { APP_ROUTES } from "@/routes/constants";
Expand All @@ -8,23 +8,23 @@ export const Footer: React.FC = () => {
return (
<footer className="flex flex-col justify-between items-center py-5 sm:px-8 md:px-[60px] border-t-[1px] border-border-table sm:flex-row gap-14 sm:gap-0 transition-spacing">
<Link to={APP_ROUTES.HOME}>
<img src={verax} alt="verax" />
<VeraxLogo />
</Link>
<div className="flex flex-col sm:flex-row gap-6 sm:gap-8 text-text-quaternary text-sm">
{INFO_LIST.map(({ title, logo, url }) => (
<a
key={title}
href={url}
target="_blank"
className="flex justify-center self-center gap-2 hover:underline hover:text-zinc-950"
className="flex justify-center items-center self-center gap-2 hover:underline"
>
{logo && <img src={logo} alt={title} className="!w-4 !h-4 self-center" />}
{logo && logo}
{title}
</a>
))}
</div>
<a href={"https://hapi.one/"} target="_blank">
<img src={hapi} alt="hapi" className="!h-[25px]" />
<HapiLogo className="!h-[25px]" />
</a>
</footer>
);
Expand Down
8 changes: 4 additions & 4 deletions explorer/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ConnectKitButton } from "connectkit";
import { ChevronDown } from "lucide-react";
import { Dispatch, SetStateAction } from "react";

import logo from "@/assets/logo/header-logo.svg";
import VeraxLogo from "@/assets/logo/header-logo.svg?react";
import { Link } from "@/components/Link";
import {
DropdownMenu,
Expand Down Expand Up @@ -34,14 +34,14 @@ export const Header: React.FC<HeaderProps> = ({ isOpened, setIsOpened }) => {
<header className="px-5 md:px-14 xl:px-[60px] py-3 justify-between items-center inline-flex">
<div className="justify-start items-center gap-6 flex self-stretch">
<Link to={APP_ROUTES.HOME} className="shrink-0 hover:opacity-70">
<img src={logo} className="h-6 xl:h-9 cursor-pointer" alt="Verax logo" />
<VeraxLogo className="xl:h-9" />
</Link>
{!isAdaptive && <NavigationList />}
</div>
<div className="justify-start items-center gap-4 flex">
<DropdownMenu>
<DropdownMenuTrigger className="DropdownMenuTrigger select-none w-[72px] p-2 rounded-md outline-none hover:bg-hover-lime20 justify-start items-center gap-2 inline-flex">
<img src={network.img} className="w-6 h-6 relative" alt="Linea logo" />
{network.img}
<ChevronDown className="header-arrow w-6 h-6 relative" />
</DropdownMenuTrigger>
<DropdownMenuContent className="flex flex-col gap-2 bg-surface-primary">
Expand All @@ -51,7 +51,7 @@ export const Header: React.FC<HeaderProps> = ({ isOpened, setIsOpened }) => {
className="flex gap-2 focus:bg-hover-lime20 cursor-pointer"
onClick={() => setNetwork(chain)}
>
<img src={chain.img} className="w-6 h-6" alt={chain.name} />
{chain.img}
{chain.name}
</DropdownMenuItem>
))}
Expand Down
13 changes: 13 additions & 0 deletions explorer/src/components/InfoBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IInfoBlockProps } from "./interface";
import { ButtonOutlined } from "../Buttons";

export const InfoBlock: React.FC<IInfoBlockProps> = ({ message, button, buttonComponent, icon }) => {
return (
<div className="h-[27.625rem] md:h-[40.875rem] flex flex-col items-center justify-center gap-6">
{icon}
<div className="text-text-darkGrey text-base font-normal">{message}</div>
{button && <ButtonOutlined name={button.name} handler={button.handler} />}
{buttonComponent && buttonComponent}
</div>
);
};
8 changes: 8 additions & 0 deletions explorer/src/components/InfoBlock/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { IButtonsProps } from "../Buttons/interface";

export interface IInfoBlockProps {
icon: JSX.Element;
message: string;
button?: IButtonsProps;
buttonComponent?: JSX.Element;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import { createConfig } from "wagmi";
import { linea, lineaTestnet } from "wagmi/chains";

import veraxColoredIcon from "@/assets/logo/verax-colored-icon.svg";
import lineaMainnetIcon from "@/assets/networks/linea-mainnet.svg";
import lineaTestnetIcon from "@/assets/networks/linea-testnet.svg";
import LineaMainnetIcon from "@/assets/networks/linea-mainnet.svg?react";
import LineaTestnetIcon from "@/assets/networks/linea-testnet.svg?react";
import { INetwork } from "@/interfaces/config";

const chains: INetwork[] = [
{
name: "Linea Mainnet",
chain: linea,
veraxEnv: VeraxSdk.DEFAULT_LINEA_MAINNET_FRONTEND,
img: lineaMainnetIcon,
img: <LineaMainnetIcon />,
network: "linea",
},
{
name: "Linea Testnet",
chain: lineaTestnet,
veraxEnv: VeraxSdk.DEFAULT_LINEA_TESTNET_FRONTEND,
img: lineaTestnetIcon,
img: <LineaTestnetIcon />,
network: "linea-testnet",
},
];
Expand Down
12 changes: 6 additions & 6 deletions explorer/src/constants/components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import gitbook from "@/assets/icons/gitbook.svg";
import veraxIcon from "@/assets/logo/verax-icon.svg";
import github from "@/assets/socials/github.svg";
import GitbookIcon from "@/assets/icons/gitbook.svg?react";
import VeraxIcon from "@/assets/logo/verax-icon.svg?react";
import GithubIcon from "@/assets/socials/github.svg?react";
import { Info } from "@/components/NavigationList/components/Info";
import { NavigationProps } from "@/interfaces/components";
import { APP_ROUTES } from "@/routes/constants";
Expand Down Expand Up @@ -31,17 +31,17 @@ export const DEFAULT_ROUTES: Array<NavigationProps> = [
export const INFO_LIST = [
{
title: "About",
logo: veraxIcon,
logo: <VeraxIcon className="!w-4 !h-4" />,
url: "https://ver.ax/",
},
{
title: "Github",
logo: github,
logo: <GithubIcon className="!w-4 !h-4" />,
url: "https://github.com/Consensys/linea-attestation-registry/tree/dev",
},
{
title: "Documentation",
logo: gitbook,
logo: <GitbookIcon className="!w-4 !h-4" />,
url: "https://docs.ver.ax/verax-documentation/",
},
];
1 change: 0 additions & 1 deletion explorer/src/enums/queryParams.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export enum EQueryParams {
PAGE = "page",
SORT_BY_DATE = "sort_by_date",
ATTESTER = "attester",
}
5 changes: 5 additions & 0 deletions explorer/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
--text-quaternary: #9096B2;
--text-blue: #2D4EC3;
--text-magenta: #D6247A;
--text-dark-grey: #646A86;

--border-card: #DAD8EC;
--border-table: #EAEAF3;
Expand All @@ -38,6 +39,10 @@
--button-secondary-text: #0D0D12;
--button-secondary-hover: #6E7491;
--button-secondary-border: #DAD8EC;

--button-outlined-text: #0C0C11;
--button-outlined-border: #DAD8EC;
--button-outlined-border-hover: #0C0C11;
}
}

Expand Down
2 changes: 1 addition & 1 deletion explorer/src/interfaces/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export interface INetwork {
name: string;
chain: Chain;
veraxEnv: Conf;
img: string;
img: JSX.Element;
network: string;
}
57 changes: 22 additions & 35 deletions explorer/src/pages/Attestations/components/ListSwitcher/index.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
import { useSearchParams } from "react-router-dom";
import { useAccount } from "wagmi";

import { EQueryParams } from "@/enums/queryParams";

export const ListSwitcher = () => {
const { address } = useAccount();

const [searchParams, setSearchParams] = useSearchParams();

const attester = searchParams.get(EQueryParams.ATTESTER);

const handleAttester = (address?: string) => {
const currentSearchParams = new URLSearchParams(searchParams);
address
? currentSearchParams.set(EQueryParams.ATTESTER, address)
: currentSearchParams.delete(EQueryParams.ATTESTER);

setSearchParams(currentSearchParams);
};
import { NavLink } from "@/components/NavLink";
import { APP_ROUTES } from "@/routes/constants";

export const ListSwitcher: React.FC = () => {
return (
<div className="inline-flex bg-slate-100 gap-2 mb-6 rounded">
<button
disabled={Boolean(!attester)}
onClick={() => handleAttester()}
className={`h-[2.1875rem] px-3 rounded text-base font-medium ${
attester ? "text-text-tertiary" : "text-white bg-gray-700"
}`}
<div className="inline-flex bg-surface-secondary gap-2 mb-6 rounded">
<NavLink
end
to={APP_ROUTES.ATTESTATIONS}
className={({ isActive }) =>
`flex items-center h-[2.1875rem] px-3 rounded text-base font-medium ${
isActive ? "text-white bg-text-secondary" : "text-text-tertiary"
}`
}
>
All attestations
</button>
<button
disabled={!address || Boolean(attester)}
onClick={() => handleAttester(address)}
className={`h-[2.1875rem] px-3 rounded text-base font-medium ${
attester ? "text-white bg-gray-700" : "text-text-tertiary"
}`}
</NavLink>
<NavLink
end
to={APP_ROUTES.MY_ATTESTATIONS}
className={({ isActive }) =>
`flex items-center h-[2.1875rem] px-3 rounded text-base font-medium ${
isActive ? "text-white bg-text-secondary" : "text-text-tertiary"
}`
}
>
My attestations
</button>
</NavLink>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { PropsWithChildren } from "react";

import { ListSwitcher } from "../ListSwitcher";

export const TitleAndSwitcher = ({ children }: PropsWithChildren) => {
return (
<div className="container mt-5 md:mt-8">
<div className="flex flex-col md:flex-row items-start md:items-center justify-between mb-6 md:mb-8 gap-6 md:gap-0">
<h1 className="text-2xl md:text-[2rem]/[2rem] font-semibold tracking-tighter zinc-950">Explore Attestations</h1>
</div>
<div>
<ListSwitcher />
{children}
</div>
</div>
);
};
26 changes: 9 additions & 17 deletions explorer/src/pages/Attestations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { SWRKeys } from "@/interfaces/swr/enum";
import { useNetworkContext } from "@/providers/network-provider/context";
import { getItemsByPage, pageBySearchParams } from "@/utils/paginationUtils";

import { ListSwitcher } from "./components/ListSwitcher";
import { TitleAndSwitcher } from "./components/TitleAndSwitcher";

export const Attestations: React.FC = () => {
const {
Expand All @@ -27,19 +27,17 @@ export const Attestations: React.FC = () => {
const totalItems = attestationsCount ?? ZERO;
const searchParams = new URLSearchParams(window.location.search);
const page = pageBySearchParams(searchParams, totalItems);
const sortByDateDirection = searchParams.get(EQueryParams.SORT_BY_DATE);

const [skip, setSkip] = useState<number>(getItemsByPage(page));

const sortByDateDirection = searchParams.get(EQueryParams.SORT_BY_DATE);
const attester = searchParams.get(EQueryParams.ATTESTER);

const { data: attestationsList } = useSWR(
`${SWRKeys.GET_ATTESTATION_LIST}/${skip}/${attester}/${sortByDateDirection}/${chain.id}`,
`${SWRKeys.GET_ATTESTATION_LIST}/${skip}/${sortByDateDirection}/${chain.id}`,
() =>
sdk.attestation.findBy(
ITEMS_PER_PAGE_DEFAULT,
skip,
attester ? { attester } : undefined,
undefined,
"attestedDate",
sortByDateDirection as OrderDirection,
),
Expand All @@ -50,16 +48,10 @@ export const Attestations: React.FC = () => {
};

return (
<div className="container mt-5 md:mt-8">
<div className="flex flex-col md:flex-row items-start md:items-center justify-between mb-6 md:mb-8 gap-6 md:gap-0">
<h1 className="text-2xl md:text-[2rem]/[2rem] font-semibold tracking-tighter zinc-950">Explore Attestations</h1>
</div>
<div>
<ListSwitcher />
{/* TODO: add skeleton for table */}
{attestationsList && <DataTable columns={columns()} data={attestationsList} />}
{attestationsCount && <Pagination itemsCount={attestationsCount} handlePage={handlePage} />}
</div>
</div>
<TitleAndSwitcher>
{/* TODO: add skeleton for table */}
<DataTable columns={columns()} data={attestationsList || []} />
{attestationsCount && <Pagination itemsCount={attestationsCount} handlePage={handlePage} />}
</TitleAndSwitcher>
);
};
6 changes: 0 additions & 6 deletions explorer/src/pages/Attestations/interfaces.ts

This file was deleted.

Loading

0 comments on commit 46439e2

Please sign in to comment.