Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions apps/dashboard/src/@/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@

/* Others */
--radius: 0.5rem;
--chart-lightness: 50%;
--chart-saturation: 50%;
}

.dark,
Expand Down Expand Up @@ -78,9 +76,6 @@
--border: 0 0% 15%;
--ring: 0 0% 30%;
--input: 0 0% 15%;

--chart-lightness: 50%;
--chart-saturation: 50%;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const Mobile: Story = {

function Component() {
return (
<div className="container py-8">
<div className="container max-w-[1150px] py-8">
<ConnectAnalyticsDashboardUI
walletUsage={createWalletStatsStub(30)}
aggregateWalletUsage={createWalletStatsStub(30)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const Mobile: Story = {

function Component() {
return (
<div className="container flex flex-col gap-6 py-8">
<div className="container flex max-w-[1150px] flex-col gap-6 py-8">
<BadgeContainer label="30 days">
<DailyConnectionsChartCard
walletStats={createWalletStatsStub(30)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export function WalletConnectorsChartCard(props: {
walletStats: WalletStats[];
isPending: boolean;
}) {
// show top 10 wallets as distinct, and combine the rest as "Others"
const topWalletsToShow = 10;
const { walletStats } = props;
const [chartToShow, setChartToShow] = useState<ChartToShow>(
"uniqueWalletsConnected",
Expand All @@ -48,40 +50,59 @@ export function WalletConnectorsChartCard(props: {
const { chartConfig, chartData } = useMemo(() => {
const _chartConfig: ChartConfig = {};
const _chartDataMap: Map<string, ChartData> = new Map();

for (const data of walletStats) {
const chartData = _chartDataMap.get(data.date);
const dataKey = data.walletType;
const walletTypeToValueMap: Map<string, number> = new Map();
// for each stat, add it in _chartDataMap
for (const stat of walletStats) {
const chartData = _chartDataMap.get(stat.date);
const { walletType } = stat;

// if no data for current day - create new entry
if (!chartData) {
_chartDataMap.set(data.date, {
time: format(new Date(data.date), "MMM dd"),
[data.walletType]: data[chartToShow],
_chartDataMap.set(stat.date, {
time: format(new Date(stat.date), "MMM dd"),
[walletType]: stat[chartToShow],
} as ChartData);
} else {
if (dataKey in chartData) {
chartData[dataKey] += data[chartToShow];
} else {
chartData[dataKey] = data[chartToShow];
}
chartData[walletType] =
(chartData[walletType] || 0) + stat[chartToShow];
}

walletTypeToValueMap.set(
walletType,
stat[chartToShow] + (walletTypeToValueMap.get(walletType) || 0),
);
}

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

for (let i = 0; i < uniqueWalletTypes.length; i++) {
const walletType = uniqueWalletTypes[i];
const walletTypesToShow = walletTypesSorted.slice(0, topWalletsToShow);
const walletTypesToTagAsOthers = walletTypesSorted.slice(topWalletsToShow);

// replace walletTypesToTagAsOthers walletType with "other"
for (const data of _chartDataMap.values()) {
for (const walletType in data) {
if (walletTypesToTagAsOthers.includes(walletType)) {
data.others = (data.others || 0) + (data[walletType] || 0);
delete data[walletType];
}
}
}

walletTypesToShow.forEach((walletType, i) => {
_chartConfig[walletType] = {
label: uniqueWalletTypes[i],
color: `hsl(${i + hueIncrement * i}deg, var(--chart-saturation), var(--chart-lightness))`,
label: walletTypesToShow[i],
color: `hsl(var(--chart-${(i % 10) + 1}))`,
};
}
});

// Add Other
walletTypesToShow.push("others");
_chartConfig.others = {
label: "Others",
color: "hsl(var(--muted-foreground))",
};

return {
chartData: Array.from(_chartDataMap.values()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const Mobile: Story = {

function Component() {
return (
<div className="container flex flex-col gap-10 py-10">
<div className="container flex max-w-[1150px] flex-col gap-10 py-10">
<BadgeContainer label="30 days">
<WalletConnectorsChartCard
walletStats={createWalletStatsStub(30)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const Mobile: Story = {

function Component() {
return (
<div className="container flex flex-col gap-10 py-10">
<div className="container flex max-w-[1150px] flex-col gap-10 py-10">
<BadgeContainer label="30 days">
<WalletDistributionChartCard
walletStats={createWalletStatsStub(30)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,98 +21,112 @@ import { useMemo, useState } from "react";
import { Pie, PieChart } from "recharts";
import { EmptyChartState, LoadingChartState } from "./EmptyChartState";

type ChartToShow = "unique" | "total";
type ChartToShow = "totalConnections" | "uniqueWalletsConnected";

type ChartData = {
walletType: string;
totalWallets: number;
uniqueWallets: number;
value: number;
fill: string;
};

const chartLabelToShow: Record<ChartToShow, string> = {
unique: "Unique Wallets",
total: "Total Wallets",
uniqueWalletsConnected: "Unique Wallets",
totalConnections: "Total Wallets",
};

export function WalletDistributionChartCard(props: {
walletStats: WalletStats[];
isPending: boolean;
}) {
// show these many top wallets as distinct, and combine the rest as "Others"
const topWalletsToShow = 10;
const { walletStats } = props;
const [chartToShow, setChartToShow] = useState<ChartToShow>("total");
const chartToShowOptions: ChartToShow[] = ["total", "unique"];
const [chartToShow, setChartToShow] =
useState<ChartToShow>("totalConnections");
const chartToShowOptions: ChartToShow[] = [
"totalConnections",
"uniqueWalletsConnected",
];

const { chartConfig, chartData, totalConnections, uniqueConnections } =
useMemo(() => {
const _chartConfig: ChartConfig = {};
const _chartDataMap: Map<
string,
{
total: number;
unique: number;
}
> = new Map();
const _chartDataMap: Map<string, number> = new Map();
const walletTypeToValueMap: Map<string, number> = new Map();

let _totalConnections = 0;
let _uniqueConnections = 0;

for (const data of walletStats) {
const chartData = _chartDataMap.get(data.walletType);

_totalConnections += data.totalConnections;
_uniqueConnections += data.uniqueWalletsConnected;

// if no data for current day - create new entry
if (!chartData) {
_chartDataMap.set(data.walletType, {
total: data.totalConnections,
unique: data.uniqueWalletsConnected,
});
} else {
_chartDataMap.set(data.walletType, {
total: chartData.total + data.totalConnections,
unique: chartData.unique + data.uniqueWalletsConnected,
});
}
for (const stat of walletStats) {
const { walletType } = stat;
const chartData = _chartDataMap.get(walletType);

_totalConnections += stat.totalConnections;
_uniqueConnections += stat.uniqueWalletsConnected;
_chartDataMap.set(walletType, (chartData || 0) + stat[chartToShow]);
walletTypeToValueMap.set(
walletType,
(walletTypeToValueMap.get(walletType) || 0) + stat[chartToShow],
);
}

// create chart config for each wallet type and assign a unique color, start from 0hue to 360hue
const uniqueWalletTypes = Array.from(
new Set(walletStats.map((data) => data.walletType)),
const walletTypesSortedByValue = Array.from(
walletTypeToValueMap.entries(),
)
.sort((a, b) => b[1] - a[1])
.map((w) => w[0]);

const walletTypesToShow = walletTypesSortedByValue.slice(
0,
topWalletsToShow,
);

const hueIncrement = 360 / uniqueWalletTypes.length;
const walletTypesToTagAsOthers =
walletTypesSortedByValue.slice(topWalletsToShow);

for (let i = 0; i < uniqueWalletTypes.length; i++) {
const walletType = uniqueWalletTypes[i];
for (const walletType of walletTypesToTagAsOthers) {
const val = _chartDataMap.get(walletType);
if (val) {
const othersVal = _chartDataMap.get("others");
_chartDataMap.set("others", othersVal ? othersVal + val : val);
}

_chartDataMap.delete(walletType);
}

const _chartConfig: ChartConfig = {};
walletTypesToShow.forEach((walletType, i) => {
_chartConfig[walletType] = {
label: uniqueWalletTypes[i],
color: `hsl(${i + hueIncrement * i}deg, var(--chart-saturation), var(--chart-lightness))`,
label: walletTypesToShow[i],
color: `hsl(var(--chart-${(i % 10) + 1}))`,
};
}
});

// Add Others
_chartConfig.others = {
label: "Others",
color: "hsl(var(--muted-foreground))",
};

const _chartData: ChartData[] = Array.from(_chartDataMap).map(
([walletType, data]) => {
return {
walletType,
totalWallets: data.total,
uniqueWallets: data.unique,
value: data,
fill: _chartConfig[walletType].color || "transparent",
};
},
);

// sort the data
_chartData.sort((a, b) => b.totalWallets - a.totalWallets);
_chartData.sort((a, b) => b.value - a.value);

return {
chartData: _chartData,
chartConfig: _chartConfig,
totalConnections: _totalConnections,
uniqueConnections: _uniqueConnections,
};
}, [walletStats]);
}, [walletStats, chartToShow]);

const disableActions = props.isPending || chartData.length === 0;
return (
Expand Down Expand Up @@ -152,23 +166,14 @@ export function WalletDistributionChartCard(props: {
getData={async () => {
const header = [
"Wallet",
"Total Connections",
"Unique Connections",
"Percentage of Total connections",
"Percentage of Unique connections",
`${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`,
`Percentage of ${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`,
];
const rows = chartData.map((d) => {
return [
// name
d.walletType,
// total connections
d.totalWallets.toString(),
// unique connections
d.uniqueWallets.toString(),
// percentage of total connections
`${((d.totalWallets / totalConnections) * 100).toFixed(2)}%`,
// percentage of unique connections
`${((d.uniqueWallets / uniqueConnections) * 100).toFixed(2)}%`,
d.value.toString(),
`${((d.value / (chartToShow === "totalConnections" ? totalConnections : uniqueConnections)) * 100).toFixed(2)}%`,
];
});
return {
Expand Down Expand Up @@ -197,7 +202,7 @@ export function WalletDistributionChartCard(props: {
valueFormatter={(v) => {
if (typeof v === "number") {
const sumValue =
chartToShow === "unique"
chartToShow === "uniqueWalletsConnected"
? uniqueConnections
: totalConnections;
const percentageValue = ((v / sumValue) * 100).toFixed(2);
Expand All @@ -210,9 +215,7 @@ export function WalletDistributionChartCard(props: {
<ChartLegend content={<ChartLegendContent />} className="" />
<Pie
data={chartData}
dataKey={
chartToShow === "unique" ? "uniqueWallets" : "totalWallets"
}
dataKey="value"
nameKey="walletType"
innerRadius={60}
strokeWidth={2}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ const walletsToPickFrom: WalletId[] = [
"com.exodus",
"app.phantom",
"com.okex.wallet",
"io.clingon",
"com.broearn",
"com.coinomi",
"com.ripio",
"com.sabay.wallet",
"io.tokoin",
"world.fncy",
"io.copiosa",
];

const pickRandomWallet = () => {
Expand Down
Loading