diff --git a/apps/dashboard/src/@/styles/globals.css b/apps/dashboard/src/@/styles/globals.css index 130d30b7afa..d89596e0c75 100644 --- a/apps/dashboard/src/@/styles/globals.css +++ b/apps/dashboard/src/@/styles/globals.css @@ -40,8 +40,6 @@ /* Others */ --radius: 0.5rem; - --chart-lightness: 50%; - --chart-saturation: 50%; } .dark, @@ -78,9 +76,6 @@ --border: 0 0% 15%; --ring: 0 0% 30%; --input: 0 0% 15%; - - --chart-lightness: 50%; - --chart-saturation: 50%; } } diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx index 6d638db5bd8..a958f48713d 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx @@ -27,7 +27,7 @@ export const Mobile: Story = { function Component() { return ( -
+
+
( "uniqueWalletsConnected", @@ -48,40 +50,59 @@ export function WalletConnectorsChartCard(props: { const { chartConfig, chartData } = useMemo(() => { const _chartConfig: ChartConfig = {}; const _chartDataMap: Map = new Map(); - - for (const data of walletStats) { - const chartData = _chartDataMap.get(data.date); - const dataKey = data.walletType; + const walletTypeToValueMap: Map = 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()), diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartChart.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartChart.stories.tsx index a3c699bbecd..cf3e3cc8fc8 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartChart.stories.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartChart.stories.tsx @@ -30,7 +30,7 @@ export const Mobile: Story = { function Component() { return ( -
+
+
= { - 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("total"); - const chartToShowOptions: ChartToShow[] = ["total", "unique"]; + const [chartToShow, setChartToShow] = + useState("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 = new Map(); + const walletTypeToValueMap: Map = 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, @@ -112,7 +126,7 @@ export function WalletDistributionChartCard(props: { totalConnections: _totalConnections, uniqueConnections: _uniqueConnections, }; - }, [walletStats]); + }, [walletStats, chartToShow]); const disableActions = props.isPending || chartData.length === 0; return ( @@ -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 { @@ -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); @@ -210,9 +215,7 @@ export function WalletDistributionChartCard(props: { } className="" /> {