Skip to content

Commit 79f029c

Browse files
committed
Only Show Top wallets in Connect Analytics, merge rest to Others + Remove dynamically generated colors (#4994)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the wallet analytics dashboard by improving the display of wallet statistics, adding new wallet types, and refining the chart configurations for better visualization of wallet usage data. ### Detailed summary - Updated `globals.css` to remove redundant CSS variables. - Added new wallet types in `storyUtils.ts`. - Adjusted container widths in several story components to a maximum width of `1150px`. - Enhanced `WalletConnectorsChartCard` to show top wallets and aggregate others. - Updated chart configuration to handle "Others" category in both `WalletConnectorsChartCard` and `WalletDistributionChartCard`. - Changed `ChartToShow` type to include `totalConnections` and `uniqueWalletsConnected`. - Modified data handling in `WalletDistributionChartCard` to aggregate wallet stats correctly. - Updated rendering logic to reflect changes in chart data and labels. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 2914a50 commit 79f029c

File tree

8 files changed

+121
-94
lines changed

8 files changed

+121
-94
lines changed

apps/dashboard/src/@/styles/globals.css

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040

4141
/* Others */
4242
--radius: 0.5rem;
43-
--chart-lightness: 50%;
44-
--chart-saturation: 50%;
4543
}
4644

4745
.dark,
@@ -78,9 +76,6 @@
7876
--border: 0 0% 15%;
7977
--ring: 0 0% 30%;
8078
--input: 0 0% 15%;
81-
82-
--chart-lightness: 50%;
83-
--chart-saturation: 50%;
8479
}
8580
}
8681

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export const Mobile: Story = {
2727

2828
function Component() {
2929
return (
30-
<div className="container py-8">
30+
<div className="container max-w-[1150px] py-8">
3131
<ConnectAnalyticsDashboardUI
3232
walletUsage={createWalletStatsStub(30)}
3333
aggregateWalletUsage={createWalletStatsStub(30)}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const Mobile: Story = {
3030

3131
function Component() {
3232
return (
33-
<div className="container flex flex-col gap-6 py-8">
33+
<div className="container flex max-w-[1150px] flex-col gap-6 py-8">
3434
<BadgeContainer label="30 days">
3535
<DailyConnectionsChartCard
3636
walletStats={createWalletStatsStub(30)}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export function WalletConnectorsChartCard(props: {
3636
walletStats: WalletStats[];
3737
isPending: boolean;
3838
}) {
39+
// show top 10 wallets as distinct, and combine the rest as "Others"
40+
const topWalletsToShow = 10;
3941
const { walletStats } = props;
4042
const [chartToShow, setChartToShow] = useState<ChartToShow>(
4143
"uniqueWalletsConnected",
@@ -48,40 +50,59 @@ export function WalletConnectorsChartCard(props: {
4850
const { chartConfig, chartData } = useMemo(() => {
4951
const _chartConfig: ChartConfig = {};
5052
const _chartDataMap: Map<string, ChartData> = new Map();
51-
52-
for (const data of walletStats) {
53-
const chartData = _chartDataMap.get(data.date);
54-
const dataKey = data.walletType;
53+
const walletTypeToValueMap: Map<string, number> = new Map();
54+
// for each stat, add it in _chartDataMap
55+
for (const stat of walletStats) {
56+
const chartData = _chartDataMap.get(stat.date);
57+
const { walletType } = stat;
5558

5659
// if no data for current day - create new entry
5760
if (!chartData) {
58-
_chartDataMap.set(data.date, {
59-
time: format(new Date(data.date), "MMM dd"),
60-
[data.walletType]: data[chartToShow],
61+
_chartDataMap.set(stat.date, {
62+
time: format(new Date(stat.date), "MMM dd"),
63+
[walletType]: stat[chartToShow],
6164
} as ChartData);
6265
} else {
63-
if (dataKey in chartData) {
64-
chartData[dataKey] += data[chartToShow];
65-
} else {
66-
chartData[dataKey] = data[chartToShow];
67-
}
66+
chartData[walletType] =
67+
(chartData[walletType] || 0) + stat[chartToShow];
6868
}
69+
70+
walletTypeToValueMap.set(
71+
walletType,
72+
stat[chartToShow] + (walletTypeToValueMap.get(walletType) || 0),
73+
);
6974
}
7075

71-
// create chart config for each wallet type and assign a unique color, start from 0hue to 360hue
72-
const uniqueWalletTypes = Array.from(
73-
new Set(walletStats.map((data) => data.walletType)),
74-
);
75-
const hueIncrement = 360 / uniqueWalletTypes.length;
76+
const walletTypesSorted = Array.from(walletTypeToValueMap.entries())
77+
.sort((a, b) => b[1] - a[1])
78+
.map((w) => w[0]);
7679

77-
for (let i = 0; i < uniqueWalletTypes.length; i++) {
78-
const walletType = uniqueWalletTypes[i];
80+
const walletTypesToShow = walletTypesSorted.slice(0, topWalletsToShow);
81+
const walletTypesToTagAsOthers = walletTypesSorted.slice(topWalletsToShow);
82+
83+
// replace walletTypesToTagAsOthers walletType with "other"
84+
for (const data of _chartDataMap.values()) {
85+
for (const walletType in data) {
86+
if (walletTypesToTagAsOthers.includes(walletType)) {
87+
data.others = (data.others || 0) + (data[walletType] || 0);
88+
delete data[walletType];
89+
}
90+
}
91+
}
7992

93+
walletTypesToShow.forEach((walletType, i) => {
8094
_chartConfig[walletType] = {
81-
label: uniqueWalletTypes[i],
82-
color: `hsl(${i + hueIncrement * i}deg, var(--chart-saturation), var(--chart-lightness))`,
95+
label: walletTypesToShow[i],
96+
color: `hsl(var(--chart-${(i % 10) + 1}))`,
8397
};
84-
}
98+
});
99+
100+
// Add Other
101+
walletTypesToShow.push("others");
102+
_chartConfig.others = {
103+
label: "Others",
104+
color: "hsl(var(--muted-foreground))",
105+
};
85106

86107
return {
87108
chartData: Array.from(_chartDataMap.values()),

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartChart.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const Mobile: Story = {
3030

3131
function Component() {
3232
return (
33-
<div className="container flex flex-col gap-10 py-10">
33+
<div className="container flex max-w-[1150px] flex-col gap-10 py-10">
3434
<BadgeContainer label="30 days">
3535
<WalletConnectorsChartCard
3636
walletStats={createWalletStatsStub(30)}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const Mobile: Story = {
3030

3131
function Component() {
3232
return (
33-
<div className="container flex flex-col gap-10 py-10">
33+
<div className="container flex max-w-[1150px] flex-col gap-10 py-10">
3434
<BadgeContainer label="30 days">
3535
<WalletDistributionChartCard
3636
walletStats={createWalletStatsStub(30)}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx

Lines changed: 66 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -21,98 +21,112 @@ import { useMemo, useState } from "react";
2121
import { Pie, PieChart } from "recharts";
2222
import { EmptyChartState, LoadingChartState } from "./EmptyChartState";
2323

24-
type ChartToShow = "unique" | "total";
24+
type ChartToShow = "totalConnections" | "uniqueWalletsConnected";
2525

2626
type ChartData = {
2727
walletType: string;
28-
totalWallets: number;
29-
uniqueWallets: number;
28+
value: number;
3029
fill: string;
3130
};
3231

3332
const chartLabelToShow: Record<ChartToShow, string> = {
34-
unique: "Unique Wallets",
35-
total: "Total Wallets",
33+
uniqueWalletsConnected: "Unique Wallets",
34+
totalConnections: "Total Wallets",
3635
};
3736

3837
export function WalletDistributionChartCard(props: {
3938
walletStats: WalletStats[];
4039
isPending: boolean;
4140
}) {
41+
// show these many top wallets as distinct, and combine the rest as "Others"
42+
const topWalletsToShow = 10;
4243
const { walletStats } = props;
43-
const [chartToShow, setChartToShow] = useState<ChartToShow>("total");
44-
const chartToShowOptions: ChartToShow[] = ["total", "unique"];
44+
const [chartToShow, setChartToShow] =
45+
useState<ChartToShow>("totalConnections");
46+
const chartToShowOptions: ChartToShow[] = [
47+
"totalConnections",
48+
"uniqueWalletsConnected",
49+
];
4550

4651
const { chartConfig, chartData, totalConnections, uniqueConnections } =
4752
useMemo(() => {
48-
const _chartConfig: ChartConfig = {};
49-
const _chartDataMap: Map<
50-
string,
51-
{
52-
total: number;
53-
unique: number;
54-
}
55-
> = new Map();
53+
const _chartDataMap: Map<string, number> = new Map();
54+
const walletTypeToValueMap: Map<string, number> = new Map();
5655

5756
let _totalConnections = 0;
5857
let _uniqueConnections = 0;
5958

60-
for (const data of walletStats) {
61-
const chartData = _chartDataMap.get(data.walletType);
62-
63-
_totalConnections += data.totalConnections;
64-
_uniqueConnections += data.uniqueWalletsConnected;
65-
66-
// if no data for current day - create new entry
67-
if (!chartData) {
68-
_chartDataMap.set(data.walletType, {
69-
total: data.totalConnections,
70-
unique: data.uniqueWalletsConnected,
71-
});
72-
} else {
73-
_chartDataMap.set(data.walletType, {
74-
total: chartData.total + data.totalConnections,
75-
unique: chartData.unique + data.uniqueWalletsConnected,
76-
});
77-
}
59+
for (const stat of walletStats) {
60+
const { walletType } = stat;
61+
const chartData = _chartDataMap.get(walletType);
62+
63+
_totalConnections += stat.totalConnections;
64+
_uniqueConnections += stat.uniqueWalletsConnected;
65+
_chartDataMap.set(walletType, (chartData || 0) + stat[chartToShow]);
66+
walletTypeToValueMap.set(
67+
walletType,
68+
(walletTypeToValueMap.get(walletType) || 0) + stat[chartToShow],
69+
);
7870
}
7971

80-
// create chart config for each wallet type and assign a unique color, start from 0hue to 360hue
81-
const uniqueWalletTypes = Array.from(
82-
new Set(walletStats.map((data) => data.walletType)),
72+
const walletTypesSortedByValue = Array.from(
73+
walletTypeToValueMap.entries(),
74+
)
75+
.sort((a, b) => b[1] - a[1])
76+
.map((w) => w[0]);
77+
78+
const walletTypesToShow = walletTypesSortedByValue.slice(
79+
0,
80+
topWalletsToShow,
8381
);
8482

85-
const hueIncrement = 360 / uniqueWalletTypes.length;
83+
const walletTypesToTagAsOthers =
84+
walletTypesSortedByValue.slice(topWalletsToShow);
8685

87-
for (let i = 0; i < uniqueWalletTypes.length; i++) {
88-
const walletType = uniqueWalletTypes[i];
86+
for (const walletType of walletTypesToTagAsOthers) {
87+
const val = _chartDataMap.get(walletType);
88+
if (val) {
89+
const othersVal = _chartDataMap.get("others");
90+
_chartDataMap.set("others", othersVal ? othersVal + val : val);
91+
}
92+
93+
_chartDataMap.delete(walletType);
94+
}
95+
96+
const _chartConfig: ChartConfig = {};
97+
walletTypesToShow.forEach((walletType, i) => {
8998
_chartConfig[walletType] = {
90-
label: uniqueWalletTypes[i],
91-
color: `hsl(${i + hueIncrement * i}deg, var(--chart-saturation), var(--chart-lightness))`,
99+
label: walletTypesToShow[i],
100+
color: `hsl(var(--chart-${(i % 10) + 1}))`,
92101
};
93-
}
102+
});
103+
104+
// Add Others
105+
_chartConfig.others = {
106+
label: "Others",
107+
color: "hsl(var(--muted-foreground))",
108+
};
94109

95110
const _chartData: ChartData[] = Array.from(_chartDataMap).map(
96111
([walletType, data]) => {
97112
return {
98113
walletType,
99-
totalWallets: data.total,
100-
uniqueWallets: data.unique,
114+
value: data,
101115
fill: _chartConfig[walletType].color || "transparent",
102116
};
103117
},
104118
);
105119

106120
// sort the data
107-
_chartData.sort((a, b) => b.totalWallets - a.totalWallets);
121+
_chartData.sort((a, b) => b.value - a.value);
108122

109123
return {
110124
chartData: _chartData,
111125
chartConfig: _chartConfig,
112126
totalConnections: _totalConnections,
113127
uniqueConnections: _uniqueConnections,
114128
};
115-
}, [walletStats]);
129+
}, [walletStats, chartToShow]);
116130

117131
const disableActions = props.isPending || chartData.length === 0;
118132
return (
@@ -152,23 +166,14 @@ export function WalletDistributionChartCard(props: {
152166
getData={async () => {
153167
const header = [
154168
"Wallet",
155-
"Total Connections",
156-
"Unique Connections",
157-
"Percentage of Total connections",
158-
"Percentage of Unique connections",
169+
`${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`,
170+
`Percentage of ${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`,
159171
];
160172
const rows = chartData.map((d) => {
161173
return [
162-
// name
163174
d.walletType,
164-
// total connections
165-
d.totalWallets.toString(),
166-
// unique connections
167-
d.uniqueWallets.toString(),
168-
// percentage of total connections
169-
`${((d.totalWallets / totalConnections) * 100).toFixed(2)}%`,
170-
// percentage of unique connections
171-
`${((d.uniqueWallets / uniqueConnections) * 100).toFixed(2)}%`,
175+
d.value.toString(),
176+
`${((d.value / (chartToShow === "totalConnections" ? totalConnections : uniqueConnections)) * 100).toFixed(2)}%`,
172177
];
173178
});
174179
return {
@@ -197,7 +202,7 @@ export function WalletDistributionChartCard(props: {
197202
valueFormatter={(v) => {
198203
if (typeof v === "number") {
199204
const sumValue =
200-
chartToShow === "unique"
205+
chartToShow === "uniqueWalletsConnected"
201206
? uniqueConnections
202207
: totalConnections;
203208
const percentageValue = ((v / sumValue) * 100).toFixed(2);
@@ -210,9 +215,7 @@ export function WalletDistributionChartCard(props: {
210215
<ChartLegend content={<ChartLegendContent />} className="" />
211216
<Pie
212217
data={chartData}
213-
dataKey={
214-
chartToShow === "unique" ? "uniqueWallets" : "totalWallets"
215-
}
218+
dataKey="value"
216219
nameKey="walletType"
217220
innerRadius={60}
218221
strokeWidth={2}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ const walletsToPickFrom: WalletId[] = [
1313
"com.exodus",
1414
"app.phantom",
1515
"com.okex.wallet",
16+
"io.clingon",
17+
"com.broearn",
18+
"com.coinomi",
19+
"com.ripio",
20+
"com.sabay.wallet",
21+
"io.tokoin",
22+
"world.fncy",
23+
"io.copiosa",
1624
];
1725

1826
const pickRandomWallet = () => {

0 commit comments

Comments
 (0)