Skip to content

Commit

Permalink
details pages for withdrawals and builders
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed May 20, 2024
1 parent 6e5fbd3 commit 6f7fc67
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 61 deletions.
143 changes: 143 additions & 0 deletions packages/nextjs/app/builders/[address]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
"use client";

import { gql, useQuery } from "@apollo/client";
import type { NextPage } from "next";
import { Address } from "~~/components/scaffold-eth";
import { type Builder, type Withdrawal } from "~~/types/streamogator";
import { customFormatEther, streamDirectory, timestampToDate } from "~~/utils/helpers";

const BUILDER = gql`
query SingleBuilder($id: String!) {
builder(id: $id) {
date
id
streamCap
streamContracts
totalWithdrawals
withdrawalsCount
}
withdrawals(where: { to: $id }) {
items {
amount
chainId
date
reason
id
streamContract
to
}
}
}
`;

interface PageProps {
params: {
address: string;
};
}

const BuilderDetails: NextPage<PageProps> = ({ params }) => {
const { data, loading, error } = useQuery(BUILDER, {
variables: { id: params.address },
fetchPolicy: "network-only", // Ensures fresh server-side fetch
});

if (loading) return <div className="text-center my-10">Loading...</div>;
if (error) return <div className="text-red-500 text-center my-10">Error : {error.message}</div>;

return (
<section className="overflow-x-auto ">
<div className="flex justify-center ">
<div className="flex flex-col justify-center items-center gap-10 my-14 max-w-[1000px]">
<Address size="3xl" address={params.address} />
<Showcase builder={data?.builder} />
<Withdrawals withdrawals={data?.withdrawals?.items} />
</div>
</div>
</section>
);
};

const Withdrawals = ({ withdrawals }: { withdrawals: Withdrawal[] }) => {
return (
<div>
<div className="overflow-x-auto w-full border border-neutral-600 rounded-xl">
<table className="table text-xl">
<thead>
<tr className="text-xl">
<th>Date</th>
<th>Amount</th>
<th>Stream</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
{withdrawals.map(withdrawal => (
<tr key={withdrawal.id}>
<td className="text-nowrap">{timestampToDate(withdrawal.date)}</td>
<td className="text-nowrap">{customFormatEther(withdrawal.amount)}</td>
<td>{streamDirectory[withdrawal.streamContract.toLowerCase()]?.name}</td>
<td>{withdrawal.reason}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
};

const Showcase = ({ builder }: { builder: Builder }) => {
if (!builder) return null;

const { withdrawalsCount, totalWithdrawals, streamCap, streamContracts, date } = builder;

const average =
withdrawalsCount > 0 ? customFormatEther(BigInt(totalWithdrawals) / BigInt(withdrawalsCount)) : "0.00";

return (
<>
<div className="stats stats-vertical sm:stats-horizontal shadow ">
<div className="stat place-items-center">
<div className="stat-title">Withdrawals</div>
<div className="stat-value">{withdrawalsCount}</div>
</div>

<div className="stat place-items-center">
<div className="stat-title">Average Amt</div>
<div className="stat-value">{average}</div>
</div>

<div className="stat place-items-center">
<div className="stat-title">Total Amt</div>
<div className="stat-value">{customFormatEther(totalWithdrawals)}</div>
</div>
<div className="stat place-items-center">
<div className="stat-title">Monthly Cap</div>
<div className="stat-value">{customFormatEther(streamCap)}</div>
</div>
</div>

<div className="overflow-x-auto w-full border border-neutral-600 rounded-xl">
<table className="table text-xl">
<tbody>
{[
{ label: "Started", value: timestampToDate(date) },
{
label: "Streams",
value: streamContracts.map(contract => streamDirectory[contract.toLowerCase()]?.name).join(", "),
},
].map((item, index) => (
<tr key={index} className="">
<th>{item.label}:</th>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
);
};

export default BuilderDetails;
16 changes: 5 additions & 11 deletions packages/nextjs/app/builders/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,9 @@ import type { NextPage } from "next";
import { formatEther } from "viem";
import { Address } from "~~/components/scaffold-eth";
import { SkeletonLoader, Table, TableControls } from "~~/components/streamogator";
import { type Builder } from "~~/types/streamogator";
import { streamDirectory, timestampToDate } from "~~/utils/helpers";

type Builder = {
id: `0x${string}`;
date: number;
streamCap: bigint;
streamContracts: `0x${string}`[];
totalWithdrawals: bigint;
withdrawalsCount: number;
};

const BUILDERS = gql`
query Builders($limit: Int!, $after: String, $orderBy: String!, $orderDirection: String!) {
builders(limit: $limit, after: $after, orderBy: $orderBy, orderDirection: $orderDirection) {
Expand Down Expand Up @@ -123,8 +115,9 @@ const BuilderTotals: NextPage = () => {
orderDirection={orderDirection}
orderBy={orderBy}
headers={headers}
hrefPrefix={"/builders/"}
rows={data.builders.items.map((builder: Builder) => {
const builderAddress = builder.id;
const builderAddress = <Address size="xl" address={builder.id} key={builder.id} />;
const startDate = timestampToDate(builder.date);
const averageWithdrawalAmount =
builder.withdrawalsCount > 0
Expand All @@ -138,7 +131,8 @@ const BuilderTotals: NextPage = () => {
.map(contract => streamDirectory[contract.toLowerCase()]?.name)
.join(", ");
return [
<Address size="xl" address={builderAddress} key={builder.id} />,
builder.id,
builderAddress,
startDate,
builder.withdrawalsCount,
averageWithdrawalAmount,
Expand Down
18 changes: 4 additions & 14 deletions packages/nextjs/app/streams/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,9 @@ import type { NextPage } from "next";
import { formatEther } from "viem";
import { Address } from "~~/components/scaffold-eth";
import { SkeletonLoader, Table } from "~~/components/streamogator";
import { type Stream } from "~~/types/streamogator";
import { timestampToDate } from "~~/utils/helpers";

type Stream = {
id: `0x${string}`; // contract address
name: string;
chainId: string;
startBlock: number;
buildersCount: number;
withdrawalsCount: number;
totalWithdrawals: bigint;
timestamp: string;
};

const STREAMS = gql`
query Streams($orderBy: String!, $orderDirection: String!) {
streams(orderBy: $orderBy, orderDirection: $orderDirection) {
Expand Down Expand Up @@ -57,8 +47,8 @@ const Streams: NextPage = () => {
};

const headers = [
{ label: "Address", key: "id", isSortable: true },
{ label: "Name", key: "name", isSortable: true },
{ label: "Address", key: "id", isSortable: true },
{ label: "Start", key: "timestamp", isSortable: true },
{ label: "Builders", key: "buildersCount", isSortable: true },
{ label: "Pulls", key: "withdrawalsCount", isSortable: true },
Expand Down Expand Up @@ -87,15 +77,15 @@ const Streams: NextPage = () => {
orderBy={orderBy}
headers={headers}
rows={data?.streams?.items.map((stream: Stream) => {
const address = <Address size="xl" address={stream.id} />;
const address = <Address size="lg" address={stream.id} />;
const name = stream.name;
const start = timestampToDate(Number(stream.timestamp));
const buildersCount = stream.buildersCount;
const withdrawalsCount = stream.withdrawalsCount;
const totalWithdrawals = ${Number(formatEther(stream.totalWithdrawals)).toFixed(2)}`;
const chainId = stream.chainId;

return [address, name, start, buildersCount, withdrawalsCount, totalWithdrawals, chainId];
return [stream.id, name, address, start, buildersCount, withdrawalsCount, totalWithdrawals, chainId];
})}
/>
)}
Expand Down
81 changes: 81 additions & 0 deletions packages/nextjs/app/withdrawals/[hash]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";

import { gql, useQuery } from "@apollo/client";
import type { NextPage } from "next";
import { Address } from "~~/components/scaffold-eth";
import { SkeletonLoader } from "~~/components/streamogator";
import { abbreviateHex, customFormatEther, timestampToDate } from "~~/utils/helpers";

const WITHDRAWAL = gql`
query SingleWithdrawal($id: String!) {
withdrawal(id: $id) {
id
date
to
amount
chainId
streamContract
reason
}
}
`;

interface PageProps {
params: {
hash: string;
};
}

const WithdrawalDetails: NextPage<PageProps> = ({ params }) => {
const { data, loading, error } = useQuery(WITHDRAWAL, {
variables: { id: params.hash },
fetchPolicy: "network-only", // Ensures fresh server-side fetch
});

if (error) return <div className="text-red-500 text-center my-10">Error : {error.message}</div>;

const skeleton = (
<div className="w-96 h-10">
<SkeletonLoader />
</div>
);

return (
<section className="overflow-x-auto ">
<div className="flex justify-center ">
<div className="flex flex-col justify-center items-center gap-10 my-14 max-w-[1000px]">
<div className="relative">
<div className="mt-1 absolute left-0 text-4xl">🧾</div>
<h1 className="text-5xl mb-0 font-paytone px-12">Withdrawal</h1>
</div>

<div className="overflow-x-auto w-full border border-neutral-600 rounded-xl">
<table className="table text-xl">
<tbody>
{[
{ label: "Date", value: loading ? skeleton : timestampToDate(data?.withdrawal?.date) },
{
label: "From",
value: loading ? skeleton : <Address size="xl" address={data?.withdrawal?.streamContract} />,
},
{ label: "To", value: loading ? skeleton : <Address size="xl" address={data?.withdrawal?.to} /> },
{ label: "Amount", value: loading ? skeleton : `${customFormatEther(data?.withdrawal?.amount)} ETH` },
{ label: "ChainId", value: loading ? skeleton : data?.withdrawal?.chainId },
{ label: "Tx Hash", value: loading ? skeleton : abbreviateHex(data?.withdrawal?.id) },
{ label: "Reason", value: loading ? skeleton : data?.withdrawal?.reason },
].map((item, index) => (
<tr key={index}>
<th>{item.label}:</th>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</section>
);
};

export default WithdrawalDetails;
35 changes: 12 additions & 23 deletions packages/nextjs/app/withdrawals/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,10 @@
import { useState } from "react";
import { gql, useQuery } from "@apollo/client";
import type { NextPage } from "next";
import { formatEther } from "viem";
import { Address } from "~~/components/scaffold-eth";
import { SkeletonLoader, Table, TableControls } from "~~/components/streamogator";
import { streamDirectory, timestampToDate } from "~~/utils/helpers";

type Withdrawal = {
id: `0x${string}`; // txHash
date: number;
to: `0x${string}`;
amount: bigint;
network: string;
streamContract: `0x${string}`;
reason: string;
};
import { type Withdrawal } from "~~/types/streamogator";
import { customFormatEther, streamDirectory, timestampToDate } from "~~/utils/helpers";

const WITHDRAWALS = gql`
query Withdrawals($limit: Int!, $after: String, $orderBy: String!, $orderDirection: String!) {
Expand All @@ -33,7 +23,7 @@ const WITHDRAWALS = gql`
date
to
amount
network
chainId
streamContract
reason
}
Expand All @@ -53,6 +43,8 @@ const Withdrawals: NextPage = () => {
fetchPolicy: "network-only", // Ensures fresh server-side fetch
});

console.log("data", data);

if (error) return <div className="text-red-500 text-center my-10">Error : {error.message}</div>;

const pageInfo = data?.withdrawals?.pageInfo;
Expand Down Expand Up @@ -92,9 +84,8 @@ const Withdrawals: NextPage = () => {
{ label: "Builder", key: "to", isSortable: true },
{ label: "Date", key: "date", isSortable: true },
{ label: "Amount", key: "amount", isSortable: true },
{ label: "Transaction", key: "id", isSortable: true },
{ label: "Stream", key: "streamContract", isSortable: true },
{ label: "Reason", key: "reason", isSortable: true },
{ label: "Chain", key: "network", isSortable: true },
];

return (
Expand Down Expand Up @@ -126,16 +117,18 @@ const Withdrawals: NextPage = () => {
orderDirection={orderDirection}
orderBy={orderBy}
headers={headers}
hrefPrefix="/withdrawals/"
rows={data.withdrawals.items.map((withdrawal: Withdrawal) => {
const builder = <Address size="xl" address={withdrawal.to} key={withdrawal.id} />;
const date = timestampToDate(withdrawal.date);
const amount = ${Number(formatEther(withdrawal.amount)).toFixed(2)}`;
const transaction = abbreviateHex(withdrawal.id);
const amount = customFormatEther(withdrawal.amount);
const id = withdrawal.id;
const stream = streamDirectory[withdrawal.streamContract]?.name || "N/A";
const reason = withdrawal.reason;
const chain = withdrawal.chainId;

// id is not displayed (only used for details page link)
// must match the order from headers
return [builder, date, amount, transaction, stream, reason];
return [id, builder, date, amount, stream, chain];
})}
/>
)}
Expand All @@ -146,7 +139,3 @@ const Withdrawals: NextPage = () => {
};

export default Withdrawals;

const abbreviateHex = (string: string) => {
return `${string.slice(0, 6)}...${string.slice(-4)}`;
};
Loading

0 comments on commit 6f7fc67

Please sign in to comment.