Skip to content

Commit ba0e1b8

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

File tree

22 files changed

+976
-840
lines changed

22 files changed

+976
-840
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: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client";
2+
import { useSetResponsiveSearchParams } from "responsive-rsc";
13
import { defineChain } from "thirdweb";
24
import { type ChainMetadata, getChainMetadata } from "thirdweb/chains";
35
import { cn } from "@/lib/utils";
@@ -6,23 +8,41 @@ import { BarChart } from "../../../components/Analytics/BarChart";
68
import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard";
79
import { EmptyAccountAbstractionChartContent } from "../../[project_slug]/(sidebar)/account-abstraction/AccountAbstractionAnalytics/SponsoredTransactionsChartCard";
810

11+
const chartConfig = {
12+
mainnet: {
13+
color: "hsl(var(--chart-1))",
14+
label: "Mainnet Chains",
15+
},
16+
testnet: {
17+
color: "hsl(var(--chart-2))",
18+
label: "Testnet Chains",
19+
},
20+
total: {
21+
color: "hsl(var(--chart-3))",
22+
label: "All Chains",
23+
},
24+
};
25+
926
export async function TotalSponsoredChartCardUI({
1027
data,
1128
aggregatedData,
12-
searchParams,
29+
selectedChart,
1330
className,
1431
onlyMainnet,
1532
title,
1633
description,
34+
selectedChartQueryParam,
1735
}: {
1836
data: UserOpStats[];
1937
aggregatedData: UserOpStats[];
20-
searchParams?: { [key: string]: string | string[] | undefined };
38+
selectedChart: string | undefined;
2139
className?: string;
2240
onlyMainnet?: boolean;
2341
title?: string;
42+
selectedChartQueryParam: string;
2443
description?: string;
2544
}) {
45+
const setResponsiveSearchParams = useSetResponsiveSearchParams();
2646
const chains = await Promise.all(
2747
data.map(
2848
(item) =>
@@ -69,21 +89,6 @@ export async function TotalSponsoredChartCardUI({
6989
total: aggregatedData.reduce((acc, curr) => acc + curr.sponsoredUsd, 0),
7090
};
7191

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-
8792
if (onlyMainnet) {
8893
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
8994
return (
@@ -106,15 +111,23 @@ export async function TotalSponsoredChartCardUI({
106111
return (
107112
<CombinedBarChartCard
108113
activeChart={
109-
(searchParams?.totalSponsored as keyof typeof chartConfig) ?? "mainnet"
114+
selectedChart && selectedChart in chartConfig
115+
? (selectedChart as keyof typeof chartConfig)
116+
: "mainnet"
110117
}
118+
onSelect={(key) => {
119+
setResponsiveSearchParams((v) => {
120+
return {
121+
...v,
122+
[selectedChartQueryParam]: key,
123+
};
124+
});
125+
}}
111126
aggregateFn={(_data, key) => processedAggregatedData[key]}
112127
chartConfig={chartConfig}
113128
className={className}
114129
data={timeSeriesData}
115-
existingQueryParams={searchParams}
116130
isCurrency
117-
queryKey="totalSponsored"
118131
title={title || "Gas Sponsored"}
119132
// Get the trend from the last two COMPLETE periods
120133
trendFn={(data, key) =>

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

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useSetResponsiveSearchParams } from "responsive-rsc";
12
import { defineChain } from "thirdweb";
23
import { type ChainMetadata, getChainMetadata } from "thirdweb/chains";
34
import { cn } from "@/lib/utils";
@@ -6,23 +7,41 @@ 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

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+
925
export async function TransactionsChartCardUI({
1026
data,
1127
aggregatedData,
12-
searchParams,
1328
className,
1429
onlyMainnet,
1530
title,
1631
description,
32+
selectedChart,
33+
selectedChartQueryParam,
1734
}: {
1835
data: TransactionStats[];
1936
aggregatedData: TransactionStats[];
20-
searchParams?: { [key: string]: string | string[] | undefined };
2137
className?: string;
2238
onlyMainnet?: boolean;
2339
title?: string;
40+
selectedChartQueryParam: string;
41+
selectedChart: string | undefined;
2442
description?: string;
2543
}) {
44+
const setResponsiveSearchParams = useSetResponsiveSearchParams();
2645
const uniqueChainIds = [
2746
...new Set(data.map((item) => item.chainId).filter(Boolean)),
2847
];
@@ -71,21 +90,6 @@ export async function TransactionsChartCardUI({
7190
total: aggregatedData.reduce((acc, curr) => acc + curr.count, 0),
7291
};
7392

74-
const chartConfig = {
75-
mainnet: {
76-
color: "hsl(var(--chart-1))",
77-
label: "Mainnet Chains",
78-
},
79-
testnet: {
80-
color: "hsl(var(--chart-2))",
81-
label: "Testnet Chains",
82-
},
83-
total: {
84-
color: "hsl(var(--chart-3))",
85-
label: "All Chains",
86-
},
87-
};
88-
8993
if (onlyMainnet) {
9094
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
9195
return (
@@ -107,15 +111,22 @@ export async function TransactionsChartCardUI({
107111
return (
108112
<CombinedBarChartCard
109113
activeChart={
110-
(searchParams?.client_transactions as keyof typeof chartConfig) ??
111-
"mainnet"
114+
selectedChart && selectedChart in chartConfig
115+
? (selectedChart as keyof typeof chartConfig)
116+
: "mainnet"
112117
}
113118
aggregateFn={(_data, key) => processedAggregatedData[key]}
114119
chartConfig={chartConfig}
115120
className={className}
121+
onSelect={(key) => {
122+
setResponsiveSearchParams((v) => {
123+
return {
124+
...v,
125+
[selectedChartQueryParam]: key,
126+
};
127+
});
128+
}}
116129
data={timeSeriesData}
117-
existingQueryParams={searchParams}
118-
queryKey="client_transactions"
119130
title={title || "Transactions"}
120131
// Get the trend from the last two COMPLETE periods
121132
trendFn={(data, key) =>

0 commit comments

Comments
 (0)