Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: As a user, I want to be able to connect my wallet to Explorer and see the list of my attestations #456

Merged
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
Loading