Skip to content

Commit

Permalink
[TOOL-3056]: Add Engine transactions bar chart, Make shadcn table hea…
Browse files Browse the repository at this point in the history
…der sticky (#5963)

<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on enhancing the user interface and functionality of various components in the dashboard application, particularly around data visualization and table displays.

### Detailed summary
- Updated `chartClassName` for better aspect ratio in multiple chart components.
- Added `tableScrollableClassName` and `tableContainerClassName` to improve table layouts.
- Modified text in `engine-overview.tsx` for clarity.
- Introduced new props in `ThirdwebBarChart` for customizable tooltips and titles.
- Implemented data processing logic in `TransactionsTable` for analytics display.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
  • Loading branch information
MananTank committed Jan 16, 2025
1 parent ea34a97 commit b511a69
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 16 deletions.
20 changes: 18 additions & 2 deletions apps/dashboard/src/@/components/blocks/charts/bar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
EmptyChartState,
LoadingChartState,
} from "../../../../components/analytics/empty-chart-state";
import { cn } from "../../../lib/utils";

type ThirdwebBarChartProps<TConfig extends ChartConfig> = {
// metadata
Expand All @@ -36,6 +37,9 @@ type ThirdwebBarChartProps<TConfig extends ChartConfig> = {
// chart className
chartClassName?: string;
isPending: boolean;
toolTipLabelFormatter?: (label: string, payload: unknown) => React.ReactNode;
hideLabel?: boolean;
titleClassName?: string;
};

export function ThirdwebBarChart<TConfig extends ChartConfig>(
Expand All @@ -45,10 +49,13 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
// if there are more than 4 keys then we should stack them by default
const variant =
props.variant || configKeys.length > 4 ? "stacked" : "grouped";

return (
<Card>
<CardHeader>
<CardTitle className="mb-2">{props.title}</CardTitle>
<CardTitle className={cn("mb-2", props.titleClassName)}>
{props.title}
</CardTitle>
{props.description && (
<CardDescription>{props.description}</CardDescription>
)}
Expand All @@ -69,7 +76,16 @@ export function ThirdwebBarChart<TConfig extends ChartConfig>(
tickMargin={10}
tickFormatter={(value) => formatDate(new Date(value), "MMM d")}
/>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<ChartTooltip
content={
<ChartTooltipContent
hideLabel={
props.hideLabel !== undefined ? props.hideLabel : true
}
labelFormatter={props.toolTipLabelFormatter}
/>
}
/>
{props.showLegend && (
<ChartLegend content={<ChartLegendContent />} />
)}
Expand Down
17 changes: 14 additions & 3 deletions apps/dashboard/src/@/components/ui/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const TableHeader = React.forwardRef<
<thead
ref={ref}
className={cn(
"border-border border-b bg-background [&_tr]:border-b",
"border-border border-b bg-background",
"sticky top-0 z-20 border-none before:absolute before:inset-0 before:border-border before:border-b",
className,
)}
{...props}
Expand Down Expand Up @@ -125,10 +126,20 @@ const TableCaption = React.forwardRef<
));
TableCaption.displayName = "TableCaption";

function TableContainer(props: { children: React.ReactNode }) {
function TableContainer(props: {
children: React.ReactNode;
className?: string;
scrollableContainerClassName?: string;
}) {
return (
<ScrollShadow
className="relative whitespace-nowrap rounded-lg border border-border bg-card"
shadowClassName="z-30"
disableTopShadow
className={cn(
"relative whitespace-nowrap rounded-lg border border-border bg-card",
props.className,
)}
scrollableClassName={props.scrollableContainerClassName}
shadowColor="hsl(var(--muted))"
>
{props.children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function UniqueWalletsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
Expand All @@ -161,7 +161,7 @@ function TotalTransactionsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
Expand All @@ -181,7 +181,7 @@ function TotalEventsChart(props: ChartProps) {
color: "hsl(var(--chart-1))",
},
}}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
Expand Down Expand Up @@ -233,7 +233,7 @@ function FunctionBreakdownChart(
},
{} as Record<string, { label: string; color: string }>,
)}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
showLegend
/>
);
Expand Down Expand Up @@ -286,7 +286,7 @@ function EventBreakdownChart(
},
{} as Record<string, { label: string; color: string }>,
)}
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
showLegend
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ function OverviewAnalytics(props: ChartProps) {
data={mergedData || []}
isPending={isPending}
showLegend
chartClassName="aspect[2] lg:aspect-[4.5]"
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export const BackendWalletsTable: React.FC<BackendWalletsTableProps> = ({
columns={columns as ColumnDef<BackendWallet, string>[]}
isPending={isPending}
isFetched={isFetched}
tableScrollableClassName="max-h-[1000px]"
onMenuClick={[
{
icon: <PencilIcon className="size-4" />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ function TransactionsSection(props: {
Transactions
</h2>
<p className="text-muted-foreground">
View transactions sent from your backend wallets in the past 24
hours.
View transactions sent from your backend wallets
</p>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ThirdwebBarChart } from "@/components/blocks/charts/bar-chart";
import { WalletAddress } from "@/components/blocks/wallet-address";
import { CopyAddressButton } from "@/components/ui/CopyAddressButton";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Badge } from "@/components/ui/badge";
import type { ChartConfig } from "@/components/ui/chart";
import {
Sheet,
SheetContent,
Expand All @@ -20,10 +22,10 @@ import {
import { createColumnHelper } from "@tanstack/react-table";
import { ChainIcon } from "components/icons/ChainIcon";
import { formatDistanceToNowStrict } from "date-fns";
import { format } from "date-fns/format";
import { format, formatDate } from "date-fns/format";
import { useAllChainsData } from "hooks/chains/allChains";
import { InfoIcon, MoveLeftIcon, MoveRightIcon } from "lucide-react";
import { type Dispatch, type SetStateAction, useState } from "react";
import { type Dispatch, type SetStateAction, useMemo, useState } from "react";
import { toTokens } from "thirdweb";
import { Button, Card, FormLabel, LinkButton, Text } from "tw-components";
import { TWTable } from "../../../../../../../../../../components/shared/TWTable";
Expand Down Expand Up @@ -256,14 +258,79 @@ export const TransactionsTable: React.FC<TransactionsTableProps> = ({
? transactions.indexOf(selectedTransaction)
: 0;

const { analyticsData, chartConfig } = useMemo(() => {
const dayToTxCountMap: Map<number, Record<string, number>> = new Map();
const uniqueStatuses = new Set<string>();

for (const tx of transactions) {
if (!tx.queuedAt || !tx.status) {
continue;
}
const normalizedDate = new Date(tx.queuedAt);
normalizedDate.setHours(0, 0, 0, 0); // normalize time
const time = normalizedDate.getTime();
const entry = dayToTxCountMap.get(time) ?? {};
entry[tx.status] = (entry[tx.status] ?? 0) + 1;
uniqueStatuses.add(tx.status);
dayToTxCountMap.set(time, entry);
}

const analyticsData = Array.from(dayToTxCountMap.entries())
.map(([day, record]) => ({
time: new Date(day).getTime(),
...record,
}))
.sort((a, b) => a.time - b.time);

const chartConfig: ChartConfig = {};
Array.from(uniqueStatuses).forEach((status, i) => {
chartConfig[status] = {
label: status.charAt(0).toUpperCase() + status.slice(1), // first letter uppercase
color:
status === "errored"
? "hsl(var(--destructive-text))"
: status === "mined"
? "hsl(var(--success-text))"
: `hsl(var(--chart-${(i % 15) + 3}))`,
};
});

return {
analyticsData,
chartConfig,
};
}, [transactions]);

return (
<>
<ThirdwebBarChart
title="Daily Transactions"
description="Transactions sent from your backend wallets per day"
config={chartConfig}
data={analyticsData}
isPending={isPending}
chartClassName="aspect-[1.5] lg:aspect-[4.5]"
titleClassName="text-xl mb-0"
hideLabel={false}
toolTipLabelFormatter={(_v, item) => {
if (Array.isArray(item)) {
const time = item[0].payload.time as number;
return formatDate(new Date(time), "MMM d, yyyy");
}
return undefined;
}}
/>

<div className="h-8" />

<TWTable
title="transactions"
data={transactions}
columns={columns}
isPending={isPending}
isFetched={isFetched}
bodyRowClassName="hover:bg-accent/50"
tableScrollableClassName="max-h-[1000px]"
onRowClick={(row) => {
setSelectedTransaction(row);
transactionDisclosure.onOpen();
Expand Down
7 changes: 6 additions & 1 deletion apps/dashboard/src/components/shared/TWTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ type TWTableProps<TRowData> = {
title: string;
bodyRowClassName?: string;
bodyRowLinkBox?: boolean;
tableContainerClassName?: string;
tableScrollableClassName?: string;
};

export function TWTable<TRowData>(tableProps: TWTableProps<TRowData>) {
Expand Down Expand Up @@ -124,7 +126,10 @@ export function TWTable<TRowData>(tableProps: TWTableProps<TRowData>) {
});

return (
<TableContainer>
<TableContainer
className={tableProps.tableContainerClassName}
scrollableContainerClassName={tableProps.tableScrollableClassName}
>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
Expand Down

0 comments on commit b511a69

Please sign in to comment.