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: addressbook page #119

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 36 additions & 0 deletions frontend/src/app/address-book/address-table-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useRouter, useSearchParams } from "next/navigation";
import sortIcon from "../../../public/assets/sortIcon.svg";
import Sort from "svg/Sort";

export default function AddressTableHeader() {
const searchParams = useSearchParams();
const router = useRouter();
const sortBy = searchParams.get("sortBy") || "";

function handleSort() {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.set("page", "1");
if (sortBy === "" || sortBy === "name-desc") {
currentUrl.searchParams.set("sortBy", "name-asc");
} else if (sortBy === "name-asc") {
currentUrl.searchParams.set("sortBy", "name-desc");
}
router.push(currentUrl.toString());
}
return (
<div className="grid grid-cols-[1fr_1.3fr_1.95fr] gap-x-[2px] text-sm">
<div className="flex items-center gap-x-3 rounded-tl-[12px] bg-[--table-header] px-[10px] py-4">
Name{" "}
<button onClick={handleSort}>
<Sort />
</button>
</div>
<div className="!rounded-none bg-[--table-header] px-[10px] py-4">
Description
</div>
<div className="rounded-tr-[12px] bg-[--table-header] px-[10px] py-4">
Address
</div>
</div>
);
}
21 changes: 21 additions & 0 deletions frontend/src/app/address-book/address-table-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AddressBookResource } from "../types";
import Link from "next/link";

export default function AddressTableRow({
address: { name, description, address },
}: {
address: AddressBookResource;
}) {
return (
<Link
href={address}
target="_blank"
rel="noopener noreferrer"
className="grid w-full cursor-pointer grid-cols-[1fr_1.3fr_1.95fr] gap-x-[2px] text-md text-[--headings] transition-all duration-300 hover:rounded hover:bg-button-secondary hover:text-text-secondary"
>
<div className="px-[10px] py-4">{name}</div>
<div className="px-[10px] py-4">{description}</div>
<div className="truncate px-[10px] py-4">{address}</div>
</Link>
);
}
49 changes: 49 additions & 0 deletions frontend/src/app/address-book/address-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use client";
import { useSearchParams } from "next/navigation";
import Pagination from "../components/ui_components/pagination";
import { AddressBookResource } from "../types";
import AddressTableHeader from "./address-table-header";
import AddressTableRow from "./address-table-row";
import { useEffect, useState } from "react";

function AddressTable({ addresses }: { addresses: AddressBookResource[] }) {
const searchParams = useSearchParams();

const [filteredAddresses, setFilteredAddresses] = useState<
AddressBookResource[]
>([]);

const page = searchParams.get("page") || "1";
const sortBy = searchParams.get("sortBy") || "";

const from = (+page - 1) * 10;
const to = from + 10;

useEffect(() => {
let result = addresses;

if (sortBy === "name-asc") {
result = result.slice().sort((a, b) => a.name.localeCompare(b.name));
} else if (sortBy === "name-desc") {
result = result.slice().sort((a, b) => b.name.localeCompare(a.name));
}

setFilteredAddresses(result);
}, [addresses, sortBy]);

return (
<div>
<AddressTableHeader />
<div className="flex flex-col gap-y-[2px] py-4">
{filteredAddresses.slice(from, to).map((address) => (
<AddressTableRow address={address} key={address.id} />
))}
</div>
<div className="mt-[34px] flex w-full justify-end">
<Pagination count={filteredAddresses.length} />
</div>
</div>
);
}

export default AddressTable;
187 changes: 72 additions & 115 deletions frontend/src/app/address-book/page.tsx
Original file line number Diff line number Diff line change
@@ -1,123 +1,80 @@
"use client";
import { useEffect, useState } from "react";
import useTheme from "../components/ui_components/hooks/useTheme";
import { Resource, columns } from "./columns";
import { DataTable } from "./data-table";
import { DataTable } from "./data-table-v1";
import { AddressBookResource } from "../types";
import { addressBookResources, searchResources } from "../utils";
import { useDebounce } from "../hooks";
import Image from "next/image";
import searchIcon from "../../../public/assets/search-icon.svg";
import AddressTable from "./address-table";
import ThemeSwitch from "../components/header/Theme";
import Search from "svg/Search";

async function getData(): Promise<Resource[]> {
let counter = 0;
return [
{
id: (counter++).toString(),
name: "Core contract",
description: "Starknet core contract on Ethereum",
address:
"https://etherscan.io/address/0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4",
},
{
id: (counter++).toString(),
name: "Verifier address (GpsStatementVerifier)",
description: "Starknet Verifier address on Ethereum",
address:
"https://etherscan.io/address/0x47312450B3Ac8b5b8e247a6bB6d523e7605bDb60",
},
{
id: (counter++).toString(),
name: "UDC",
description: "OpenZeppelin Universal Deployer Contract",
address:
"https://starkscan.co/contract/0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf",
},
{
id: (counter++).toString(),
name: "STRK",
description: "Stark Token",
address:
"https://starkscan.co/contract/0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
},
{
id: (counter++).toString(),
name: "vSTRK",
description: "Starknet Voting Token",
address:
"https://starkscan.co/contract/0x0782f0ddca11d9950bc3220e35ac82cf868778edb67a5e58b39838544bc4cd0f",
},
{
id: (counter++).toString(),
name: "WBTC",
description: "Wrapped BTC",
address:
"https://starkscan.co/contract/0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
},
{
id: (counter++).toString(),
name: "USDC",
description: "USD Coin",
address:
"https://starkscan.co/contract/0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
},
{
id: (counter++).toString(),
name: "USDT",
description: "Tether USD",
address:
"https://starkscan.co/contract/0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
},
{
id: (counter++).toString(),
name: "ETH",
description: "Ether",
address:
"https://starkscan.co/contract/0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
},
{
id: (counter++).toString(),
name: "DAI",
description: "Dai Stablecoin",
address:
"https://starkscan.co/contract/0x05574eb6b8789a91466f902c380d978e472db68170ff82a5b650b95a58ddf4ad",
},
{
id: (counter++).toString(),
name: "wstETH",
description: "Wrapped liquid staked Ether 2.0",
address:
"https://starkscan.co/contract/0x42b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2",
},
{
id: (counter++).toString(),
name: "rETH",
description: "Rocket Poll Eth",
address:
"https://starkscan.co/contract/0x0319111a5037cbec2b3e638cc34a3474e2d2608299f3e62866e9cc683208c610",
},
{
id: (counter++).toString(),
name: "R",
description: "R Stablecoin",
address:
"https://starkscan.co/contract/0x01fa2fb85f624600112040e1f3a848f53a37ed5a7385810063d5fe6887280333",
},
{
id: (counter++).toString(),
name: "FRAX",
description: "Frax",
address:
"https://starkscan.co/contract/0x009c6b4fb13dfaa025c1383ed6190af8ed8cbb09d9588a3bb020feb152442406",
},
{
id: (counter++).toString(),
name: "UNI",
description: "Uniswap",
address:
"https://starkscan.co/contract/0x049210ffc442172463f3177147c1aeaa36c51d152c1b0630f2364c300d4f48ee",
},
];
}
export default function Page() {
const { theme, changeTheme } = useTheme();
const [addresses] = useState<AddressBookResource[]>(addressBookResources);
const [filteredAddresses, setFilteredAddresses] = useState<
AddressBookResource[]
>([]);
const [openMenu] = useState(false);
const [search, setSearch] = useState("");
const debouncedSearch = useDebounce(search);

export default async function Page() {
const data = await getData();
useEffect(() => {
const loadAddresses = async () => {
const searchResult = debouncedSearch.trim()
? await searchResources({
resources: addresses,
search: debouncedSearch,
})
: [];
setFilteredAddresses(searchResult);
};
loadAddresses();
}, [debouncedSearch]);

return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={data} />
<div className="relative w-full bg-[--background]">
<div className="w-full bg-primary-gradient px-[100px] py-[30px]">
<div className="relative mb-[95px] flex flex-wrap items-center justify-between">
<div className="flex items-center gap-x-[9px]">
<div className="w-[18.75rem]">
<img
src="/assets/logo.svg"
alt="logo"
className="h-full w-full"
/>
</div>
<h4 className="border-l-[1.75px] border-[#141925] px-2 py-1 text-[24px] uppercase italic leading-7 text-[#141925]">
ADDRESSBOOK
</h4>
</div>
<ThemeSwitch action={changeTheme} theme={theme} />
</div>
<div className="relative mx-auto w-fit">
<input
type="text"
className="w-[800px] rounded-2xl bg-[--link-card] px-6 py-5 pl-[60px] text-l leading-[30px] text-[#141925] placeholder:text-[#7A7A7A] dark:text-white"
placeholder="Search keywords, contract addreses"
name="search"
onChange={(e) => setSearch(e.target.value)}
/>
<div className="absolute left-6 top-[22px] z-10 h-6 w-6">
<Search />
</div>
</div>
</div>
<div className="h-full w-full px-9 pb-[74px] pt-4 text-[--headings]">
<AddressTable
addresses={
filteredAddresses.length > 0 && search.length > 0
? filteredAddresses
: addresses
}
/>
</div>
</div>
);
}
1 change: 0 additions & 1 deletion frontend/src/app/components/ui_components/SortBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export default function SortBy({ options }: { options: any }) {

function handleChange(e: any) {
const currentUrl = new URL(window.location.href);
let currentSortBy = currentUrl.searchParams.get("sortBy");
if (e.target.value === "") {
currentUrl.searchParams.delete("sortBy");
router.push(currentUrl.toString());
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
:root {
--foreground: #7a7a7a;
--background: #ffffff;
--table-header: #f9fafb;
--headings: #141925;
--add-token-border: #141925;
--backdrop: #ffffff4d;
Expand All @@ -20,6 +21,7 @@
:root {
--foreground: #eaeaea;
--background: #1f1f1f;
--table-header: #332920;
--headings: #eaeaea;
--add-token-border: #141925;
--backdrop: transparent;
Expand All @@ -30,6 +32,7 @@
[data-theme="light"] {
--foreground: #7a7a7a;
--background: #ffffff;
--table-header: #f9fafb;
--headings: #141925;
--add-token-border: #141925;
--backdrop: #ffffff4d;
Expand All @@ -39,6 +42,7 @@
[data-theme="dark"] {
--foreground: #eaeaea;
--background: #1f1f1f;
--table-header: #332920;
--headings: #eaeaea;
--add-token-border: #ffffff;
--backdrop: transparent;
Expand All @@ -59,9 +63,7 @@
background-color 0.5s linear,
color 0.5s linear;
}
h1 {
color: var(--headings);
}

.add-token {
border-color: var(--add-token-border);
transition: border-color 0.3s linear;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Home() {
{/* HERO --> */}
<section className="pt-[clamp(200px,25vh,650px)]">
<div className="mx-auto flex max-w-[850px] flex-col gap-8 p-8 text-center">
<h1 className="text-3xl">
<h1 className="text-3xl text-[--headings]">
Everything you need to buidl dApps on Ethereum
</h1>
<p className="text-md">
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/app/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ export interface WikipediaResource {
url: string;
category: string;
}

export interface AddressBookResource {
id: string;
name: string;
description: string;
address: string;
}
Loading
Loading