Skip to content

Commit e391b4f

Browse files
committed
Dashboard: Improved chart responsiveness, code cleanup
1 parent abbdb0f commit e391b4f

File tree

23 files changed

+1102
-898
lines changed

23 files changed

+1102
-898
lines changed

apps/dashboard/src/@/components/analytics/date-range-selector.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export function DateRangeSelector(props: {
1818
}) {
1919
const { range, setRange } = props;
2020
const daysDiff = differenceInCalendarDays(range.to, range.from);
21+
2122
const matchingRange =
2223
normalizeTime(range.to).getTime() === normalizeTime(new Date()).getTime()
2324
? durationPresets.find((preset) => preset.days === daysDiff)
@@ -85,7 +86,7 @@ export function getLastNDaysRange(id: DurationId) {
8586
throw new Error(`Invalid duration id: ${id}`);
8687
}
8788

88-
const todayDate = new Date(Date.now() + 1000 * 60 * 60 * 24); // add 1 day to avoid timezone issues
89+
const todayDate = new Date(Date.now());
8990

9091
const value: Range = {
9192
from: subDays(todayDate, durationInfo.days),

apps/dashboard/src/@/components/analytics/range-selector.tsx

Lines changed: 0 additions & 104 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import {
4+
useResponsiveSearchParams,
5+
useSetResponsiveSearchParams,
6+
} from "responsive-rsc";
7+
import {
8+
DateRangeSelector,
9+
type DurationId,
10+
} from "@/components/analytics/date-range-selector";
11+
import { IntervalSelector } from "@/components/analytics/interval-selector";
12+
import { getFiltersFromSearchParams, normalizeTimeISOString } from "@/lib/time";
13+
14+
export function ResponsiveTimeFilters(props: { defaultRange: DurationId }) {
15+
const responsiveSearchParams = useResponsiveSearchParams();
16+
const setResponsiveSearchParams = useSetResponsiveSearchParams();
17+
const { range, interval } = getFiltersFromSearchParams({
18+
defaultRange: props.defaultRange,
19+
from: responsiveSearchParams.from,
20+
interval: responsiveSearchParams.interval,
21+
to: responsiveSearchParams.to,
22+
});
23+
24+
return (
25+
<div className="flex justify-end gap-3 flex-col lg:flex-row">
26+
<DateRangeSelector
27+
className="rounded-full"
28+
range={range}
29+
setRange={(newRange) => {
30+
setResponsiveSearchParams((v) => {
31+
const newParams = {
32+
...v,
33+
from: normalizeTimeISOString(newRange.from),
34+
to: normalizeTimeISOString(newRange.to),
35+
};
36+
return newParams;
37+
});
38+
}}
39+
/>
40+
<IntervalSelector
41+
className="bg-card rounded-full"
42+
intervalType={interval}
43+
setIntervalType={(newInterval) => {
44+
setResponsiveSearchParams((v) => {
45+
const newParams = {
46+
...v,
47+
interval: newInterval,
48+
};
49+
return newParams;
50+
});
51+
}}
52+
/>
53+
</div>
54+
);
55+
}

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,53 @@
1-
import { defineChain } from "thirdweb";
2-
import { type ChainMetadata, getChainMetadata } from "thirdweb/chains";
1+
"use client";
2+
import { useSetResponsiveSearchParams } from "responsive-rsc";
3+
import type { ChainMetadata } from "thirdweb/chains";
34
import { cn } from "@/lib/utils";
45
import type { UserOpStats } from "@/types/analytics";
56
import { BarChart } from "../../../components/Analytics/BarChart";
67
import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard";
78
import { EmptyAccountAbstractionChartContent } from "../../[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/SponsoredTransactionsChartCard";
89

9-
export async function TotalSponsoredChartCardUI({
10-
data,
11-
aggregatedData,
12-
searchParams,
10+
const chartConfig = {
11+
mainnet: {
12+
color: "hsl(var(--chart-1))",
13+
label: "Mainnet Chains",
14+
},
15+
testnet: {
16+
color: "hsl(var(--chart-2))",
17+
label: "Testnet Chains",
18+
},
19+
total: {
20+
color: "hsl(var(--chart-3))",
21+
label: "All Chains",
22+
},
23+
};
24+
25+
export function TotalSponsoredChartCardUI({
26+
processedAggregatedData,
27+
selectedChart,
1328
className,
1429
onlyMainnet,
1530
title,
31+
chains,
32+
data,
1633
description,
34+
selectedChartQueryParam,
1735
}: {
1836
data: UserOpStats[];
19-
aggregatedData: UserOpStats[];
20-
searchParams?: { [key: string]: string | string[] | undefined };
37+
selectedChart: string | undefined;
2138
className?: string;
2239
onlyMainnet?: boolean;
2340
title?: string;
41+
selectedChartQueryParam: string;
2442
description?: string;
43+
chains: ChainMetadata[];
44+
processedAggregatedData: {
45+
mainnet: number;
46+
testnet: number;
47+
total: number;
48+
};
2549
}) {
26-
const chains = await Promise.all(
27-
data.map(
28-
(item) =>
29-
// eslint-disable-next-line no-restricted-syntax
30-
item.chainId && getChainMetadata(defineChain(Number(item.chainId))),
31-
),
32-
).then((chains) => chains.filter((c) => c) as ChainMetadata[]);
50+
const setResponsiveSearchParams = useSetResponsiveSearchParams();
3351

3452
// Process data to combine by date and chain type
3553
const dateMap = new Map<string, { mainnet: number; testnet: number }>();
@@ -55,35 +73,6 @@ export async function TotalSponsoredChartCardUI({
5573
}))
5674
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
5775

58-
const processedAggregatedData = {
59-
mainnet: aggregatedData
60-
.filter(
61-
(d) => !chains.find((c) => c.chainId === Number(d.chainId))?.testnet,
62-
)
63-
.reduce((acc, curr) => acc + curr.sponsoredUsd, 0),
64-
testnet: aggregatedData
65-
.filter(
66-
(d) => chains.find((c) => c.chainId === Number(d.chainId))?.testnet,
67-
)
68-
.reduce((acc, curr) => acc + curr.sponsoredUsd, 0),
69-
total: aggregatedData.reduce((acc, curr) => acc + curr.sponsoredUsd, 0),
70-
};
71-
72-
const chartConfig = {
73-
mainnet: {
74-
color: "hsl(var(--chart-1))",
75-
label: "Mainnet Chains",
76-
},
77-
testnet: {
78-
color: "hsl(var(--chart-2))",
79-
label: "Testnet Chains",
80-
},
81-
total: {
82-
color: "hsl(var(--chart-3))",
83-
label: "All Chains",
84-
},
85-
};
86-
8776
if (onlyMainnet) {
8877
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
8978
return (
@@ -106,15 +95,23 @@ export async function TotalSponsoredChartCardUI({
10695
return (
10796
<CombinedBarChartCard
10897
activeChart={
109-
(searchParams?.totalSponsored as keyof typeof chartConfig) ?? "mainnet"
98+
selectedChart && selectedChart in chartConfig
99+
? (selectedChart as keyof typeof chartConfig)
100+
: "mainnet"
110101
}
102+
onSelect={(key) => {
103+
setResponsiveSearchParams((v) => {
104+
return {
105+
...v,
106+
[selectedChartQueryParam]: key,
107+
};
108+
});
109+
}}
111110
aggregateFn={(_data, key) => processedAggregatedData[key]}
112111
chartConfig={chartConfig}
113112
className={className}
114113
data={timeSeriesData}
115-
existingQueryParams={searchParams}
116114
isCurrency
117-
queryKey="totalSponsored"
118115
title={title || "Gas Sponsored"}
119116
// Get the trend from the last two COMPLETE periods
120117
trendFn={(data, key) =>

0 commit comments

Comments
 (0)