diff --git a/apps/dashboard/src/@/api/analytics.ts b/apps/dashboard/src/@/api/analytics.ts index 601e3e0709a..d74af46a22f 100644 --- a/apps/dashboard/src/@/api/analytics.ts +++ b/apps/dashboard/src/@/api/analytics.ts @@ -1,42 +1,12 @@ import { fetchAnalytics } from "data/analytics/fetch-analytics"; - -export interface WalletStats { - date: string; - uniqueWalletsConnected: number; - totalConnections: number; - walletType: string; -} - -export interface WalletUserStats { - date: string; - newUsers: number; - returningUsers: number; - totalUsers: number; -} - -export interface InAppWalletStats { - date: string; - authenticationMethod: string; - uniqueWalletsConnected: number; -} - -export interface EcosystemWalletStats extends InAppWalletStats {} - -export interface UserOpStats { - date: string; - successful: number; - failed: number; - sponsoredUsd: number; - chainId?: string; -} - -interface AnalyticsQueryParams { - clientId?: string; - accountId?: string; - from?: Date; - to?: Date; - period?: "day" | "week" | "month" | "year" | "all"; -} +import type { + AnalyticsQueryParams, + InAppWalletStats, + RpcMethodStats, + UserOpStats, + WalletStats, + WalletUserStats, +} from "types/analytics"; function buildSearchParams(params: AnalyticsQueryParams): URLSearchParams { const searchParams = new URLSearchParams(); @@ -115,6 +85,27 @@ export async function getUserOpUsage( return json.data as UserOpStats[]; } +export async function getRpcMethodUsage( + params: AnalyticsQueryParams, +): Promise { + const searchParams = buildSearchParams(params); + const res = await fetchAnalytics( + `v1/rpc/evm-methods?${searchParams.toString()}`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + }, + ); + + if (res?.status !== 200) { + console.error("Failed to fetch RPC method usage"); + return []; + } + + const json = await res.json(); + return json.data as RpcMethodStats[]; +} + export async function getWalletUsers( params: AnalyticsQueryParams, ): Promise { @@ -135,3 +126,21 @@ export async function getWalletUsers( const json = await res.json(); return json.data as WalletUserStats[]; } + +export async function isProjectActive( + params: AnalyticsQueryParams, +): Promise { + const searchParams = buildSearchParams(params); + const res = await fetchAnalytics(`v1/active?${searchParams.toString()}`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + if (res?.status !== 200) { + console.error("Failed to fetch project active status"); + return false; + } + + const json = await res.json(); + return json.data.isActive as boolean; +} diff --git a/apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts b/apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts index 006758f1227..e55d1218577 100644 --- a/apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts +++ b/apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts @@ -1,4 +1,3 @@ -import type { UserOpStats } from "@/api/analytics"; import type { Team } from "@/api/team"; import { type Query, @@ -9,6 +8,7 @@ import { import { THIRDWEB_ANALYTICS_API_HOST, THIRDWEB_API_HOST } from "constants/urls"; import { useAllChainsData } from "hooks/chains/allChains"; import invariant from "tiny-invariant"; +import type { UserOpStats } from "types/analytics"; import { accountKeys, apiKeys, authorizedWallets } from "../cache-keys"; import { useLoggedInUser } from "./useLoggedInUser"; diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx index 325a2e418b6..b37dddd86bc 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx @@ -1,7 +1,7 @@ -import type { UserOpStats } from "@/api/analytics"; import { cn } from "@/lib/utils"; import { defineChain } from "thirdweb"; import { type ChainMetadata, getChainMetadata } from "thirdweb/chains"; +import type { UserOpStats } from "types/analytics"; import { EmptyAccountAbstractionChartContent } from "../../../../../components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard"; import { BarChart } from "../../../components/Analytics/BarChart"; import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard"; diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx index 5ca8358ac85..026f703378b 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx @@ -10,7 +10,7 @@ import type { InAppWalletStats, WalletStats, WalletUserStats, -} from "@/api/analytics"; +} from "types/analytics"; import { type DurationId, diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/EcosystemWalletUsersChartCard.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/EcosystemWalletUsersChartCard.tsx index ceb8b62a3ed..ba90b099cc8 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/EcosystemWalletUsersChartCard.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/EcosystemWalletUsersChartCard.tsx @@ -1,5 +1,4 @@ "use client"; -import type { EcosystemWalletStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -21,6 +20,7 @@ import { format } from "date-fns"; import { formatTickerNumber } from "lib/format-utils"; import { useMemo } from "react"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import type { EcosystemWalletStats } from "types/analytics"; type ChartData = Record & { time: string; // human readable date diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/Summary.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/Summary.tsx index 6d26698daa5..bbd93ee53c6 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/Summary.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/Summary.tsx @@ -1,6 +1,6 @@ -import type { EcosystemWalletStats } from "@/api/analytics"; import { Stat } from "components/analytics/stat"; import { ActivityIcon, UserIcon } from "lucide-react"; +import type { EcosystemWalletStats } from "types/analytics"; export function EcosystemWalletsSummary(props: { allTimeStats: EcosystemWalletStats[] | undefined; diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/ecosystem-header.client.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/ecosystem-header.client.tsx index a97b168b327..75e9c0054f0 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/ecosystem-header.client.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/components/ecosystem-header.client.tsx @@ -1,5 +1,4 @@ "use client"; -import type { EcosystemWalletStats } from "@/api/analytics"; import { CopyButton } from "@/components/ui/CopyButton"; import { Spinner } from "@/components/ui/Spinner/Spinner"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; @@ -24,6 +23,7 @@ import { } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; +import type { EcosystemWalletStats } from "types/analytics"; import { useEcosystemList } from "../../../hooks/use-ecosystem-list"; import type { Ecosystem } from "../../../types"; import { EcosystemWalletsSummary } from "../analytics/components/Summary"; diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCard.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCard.stories.tsx new file mode 100644 index 00000000000..1bacf70f93d --- /dev/null +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCard.stories.tsx @@ -0,0 +1,86 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { BadgeContainer, mobileViewport } from "stories/utils"; +import type { RpcMethodStats } from "types/analytics"; +import { RpcMethodBarChartCardUI } from "./RpcMethodBarChartCardUI"; + +const meta = { + title: "Analytics/RpcMethodBarChartCard", + component: Component, + parameters: { + layout: "centered", + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Desktop: Story = { + parameters: { + viewport: { defaultViewport: "desktop" }, + }, +}; + +export const Mobile: Story = { + parameters: { + viewport: mobileViewport("iphone14"), + }, +}; + +const generateTimeSeriesData = ( + days: number, + methods: string[], + emptyData = false, +) => { + const data: RpcMethodStats[] = []; + const today = new Date(); + + for (let i = days - 1; i >= 0; i--) { + const date = new Date(today); + date.setDate(date.getDate() - i); + + for (const method of methods) { + data.push({ + date: date.toISOString(), + evmMethod: method, + count: emptyData ? 0 : Math.floor(Math.random() * 1000) + 100, + }); + } + } + + return data; +}; + +const commonMethods = [ + "eth_call", + "eth_getBalance", + "eth_getTransactionReceipt", + "eth_blockNumber", +]; + +function Component() { + return ( +
+ + + + + + + + + + + + + + + +
+ ); +} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCardUI.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCardUI.tsx new file mode 100644 index 00000000000..6f174a29ab6 --- /dev/null +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/RpcMethodBarChartCardUI.tsx @@ -0,0 +1,163 @@ +"use client"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + type ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/components/ui/chart"; +import { formatTickerNumber } from "lib/format-utils"; +import { useMemo } from "react"; +import { + Bar, + CartesianGrid, + BarChart as RechartsBarChart, + XAxis, + YAxis, +} from "recharts"; +import type { RpcMethodStats } from "types/analytics"; +import { EmptyStateCard } from "../../../../components/Analytics/EmptyStateCard"; + +export function RpcMethodBarChartCardUI({ + rawData, +}: { rawData: RpcMethodStats[] }) { + const uniqueMethods = useMemo( + () => Array.from(new Set(rawData.map((d) => d.evmMethod))), + [rawData], + ); + const uniqueDates = useMemo( + () => Array.from(new Set(rawData.map((d) => d.date))), + [rawData], + ); + + const data = useMemo(() => { + return uniqueDates.map((date) => { + const dateData: { [key: string]: string | number } = { date }; + for (const method of uniqueMethods) { + const methodData = rawData.find( + (d) => d.date === date && d.evmMethod === method, + ); + dateData[method] = methodData?.count ?? 0; + } + + // If we have too many methods to display well, add "other" and group the lowest keys for each time period + if (uniqueMethods.length > 5) { + // If we haven't added "other" as a key yet, add it + if (!uniqueMethods.includes("Other")) { + uniqueMethods.push("Other"); + } + + // Sort the methods by their count for the time period + const sortedMethods = uniqueMethods + .filter((m) => m !== "Other") + .sort( + (a, b) => + ((dateData[b] as number) ?? 0) - ((dateData[a] as number) ?? 0), + ); + + dateData.Other = 0; + for (const method of sortedMethods.slice(5, sortedMethods.length)) { + dateData.Other += (dateData[method] as number) ?? 0; + delete dateData[method]; + } + } + return dateData; + }); + }, [uniqueDates, uniqueMethods, rawData]); + + const config: ChartConfig = useMemo(() => { + const config: ChartConfig = {}; + for (const method of uniqueMethods) { + config[method] = { + label: method, + }; + } + return config; + }, [uniqueMethods]); + + if ( + data.length === 0 || + data.every((date) => + Object.keys(date).every((k) => k === "date" || date[k] === 0), + ) + ) { + return ; + } + + return ( + + +
+ RPC Methods +
+
+ + + + + { + const date = new Date(value); + return date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + }); + }} + /> + formatTickerNumber(value)} + /> + { + return new Date(value).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + }} + valueFormatter={(v: unknown) => + formatTickerNumber(v as number) + } + /> + } + /> + {uniqueMethods.map((method, idx) => ( + + ))} + + + +
+ ); +} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/index.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/index.tsx new file mode 100644 index 00000000000..59121d1077a --- /dev/null +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/RpcMethodBarChartCard/index.tsx @@ -0,0 +1,26 @@ +import { getRpcMethodUsage } from "@/api/analytics"; +import { LoadingChartState } from "components/analytics/empty-chart-state"; +import { Suspense } from "react"; +import type { AnalyticsQueryParams } from "types/analytics"; +import { RpcMethodBarChartCardUI } from "./RpcMethodBarChartCardUI"; + +export function RpcMethodBarChartCard(props: AnalyticsQueryParams) { + return ( + // TODO: Add better LoadingChartState + + + + } + > + + + ); +} + +async function RpcMethodBarChartCardAsync(props: AnalyticsQueryParams) { + const rawData = await getRpcMethodUsage(props); + + return ; +} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/ConnectAnalyticsDashboardUI.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/ConnectAnalyticsDashboardUI.tsx index 2fde0423981..5290797c0fd 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/ConnectAnalyticsDashboardUI.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/ConnectAnalyticsDashboardUI.tsx @@ -1,8 +1,3 @@ -import type { - InAppWalletStats, - UserOpStats, - WalletStats, -} from "@/api/analytics"; import { Button } from "@/components/ui/button"; import type { Range } from "components/analytics/date-range-selector"; import { Stat } from "components/analytics/stat"; @@ -12,6 +7,11 @@ import { differenceInDays } from "date-fns"; import { ArrowRightIcon, CableIcon, WalletCardsIcon } from "lucide-react"; import Link from "next/link"; import { useMemo } from "react"; +import type { + InAppWalletStats, + UserOpStats, + WalletStats, +} from "types/analytics"; import { DateRangeSelector } from "../../../../../../components/analytics/date-range-selector"; import { IntervalSelector } from "../../../../../../components/analytics/interval-selector"; import { DailyConnectionsChartCard } from "./_components/DailyConnectionsChartCard"; diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.tsx index d78d05f256c..dca46eb2bdb 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.tsx @@ -1,6 +1,5 @@ "use client"; -import type { WalletStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -35,6 +34,7 @@ import { XAxis, YAxis, } from "recharts"; +import type { WalletStats } from "types/analytics"; import { formatTickerNumber } from "../../../../../../../lib/format-utils"; type ChartToShow = "uniqueWallets" | "totalWallets"; diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx index ad09876a7d0..2cad2186c48 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx @@ -1,6 +1,5 @@ "use client"; -import type { WalletStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -27,6 +26,7 @@ import { DocLink } from "components/shared/DocLink"; import { format } from "date-fns"; import { useMemo, useState } from "react"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import type { WalletStats } from "types/analytics"; import { formatTickerNumber, formatWalletType, diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx index c3ef0293009..e475121ccdc 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx @@ -1,6 +1,5 @@ "use client"; -import type { WalletStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -26,6 +25,7 @@ import { TypeScriptIcon } from "components/icons/brand-icons/TypeScriptIcon"; import { DocLink } from "components/shared/DocLink"; import { useMemo, useState } from "react"; import { Pie, PieChart } from "recharts"; +import type { WalletStats } from "types/analytics"; import { formatTickerNumber, formatWalletType, diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts index 0a75401f312..bb64da83daf 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts @@ -1,5 +1,5 @@ -import type { WalletStats } from "@/api/analytics"; import type { WalletId } from "thirdweb/wallets"; +import type { WalletStats } from "types/analytics"; const walletsToPickFrom: WalletId[] = [ "io.metamask", diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx index d5b0f0e8e26..857f7b5ca2f 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/page.tsx @@ -2,23 +2,24 @@ import { notFound } from "next/navigation"; import { getProject } from "@/api/projects"; -import type { - InAppWalletStats, - UserOpStats, - WalletStats, - WalletUserStats, -} from "@/api/analytics"; import { type DurationId, type Range, getLastNDaysRange, } from "components/analytics/date-range-selector"; +import type { + InAppWalletStats, + UserOpStats, + WalletStats, + WalletUserStats, +} from "types/analytics"; import { getInAppWalletUsage, getUserOpUsage, getWalletConnections, getWalletUsers, + isProjectActive, } from "@/api/analytics"; import { EmptyStateCard } from "app/team/components/Analytics/EmptyStateCard"; import { @@ -31,6 +32,7 @@ import { AnalyticsHeader } from "../../components/Analytics/AnalyticsHeader"; import { CombinedBarChartCard } from "../../components/Analytics/CombinedBarChartCard"; import { EmptyState } from "../../components/Analytics/EmptyState"; import { PieChartCard } from "../../components/Analytics/PieChartCard"; +import { RpcMethodBarChartCard } from "./components/RpcMethodBarChartCard"; interface PageParams { team_slug: string; @@ -65,6 +67,8 @@ export default async function ProjectOverviewPage(props: PageProps) { notFound(); } + const isActive = await isProjectActive({ clientId: project.publishableKey }); + // Fetch all analytics data in parallel const [ walletConnections, @@ -109,12 +113,6 @@ export default async function ProjectOverviewPage(props: PageProps) { }), ]); - const isEmpty = - !walletUserStatsTimeSeries.some((w) => w.totalUsers !== 0) && - walletConnections.length === 0 && - inAppWalletUsage.length === 0 && - userOpUsage.length === 0; - return (
@@ -124,7 +122,7 @@ export default async function ProjectOverviewPage(props: PageProps) { range={range} />
- {isEmpty ? ( + {!isActive ? (
@@ -150,6 +148,12 @@ export default async function ProjectOverviewPage(props: PageProps) { link="https://portal.thirdweb.com/connect/quickstart" /> )} +
{walletConnections.length > 0 ? ( diff --git a/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.stories.tsx b/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.stories.tsx index 4a7e4783f55..7a7ecbc8b3f 100644 --- a/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.stories.tsx +++ b/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.stories.tsx @@ -1,6 +1,6 @@ -import type { InAppWalletStats } from "@/api/analytics"; import type { Meta, StoryObj } from "@storybook/react"; import type { InAppWalletAuth } from "thirdweb/wallets"; +import type { InAppWalletStats } from "types/analytics"; import { BadgeContainer, mobileViewport } from "../../../stories/utils"; import { InAppWalletUsersChartCardUI } from "./InAppWalletUsersChartCard"; diff --git a/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.tsx b/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.tsx index d02442839c0..55d71489d41 100644 --- a/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.tsx +++ b/apps/dashboard/src/components/embedded-wallets/Analytics/InAppWalletUsersChartCard.tsx @@ -1,5 +1,4 @@ "use client"; -import type { InAppWalletStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -21,6 +20,7 @@ import { DocLink } from "components/shared/DocLink"; import { format } from "date-fns"; import { useMemo } from "react"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import type { InAppWalletStats } from "types/analytics"; import { formatTickerNumber } from "../../../lib/format-utils"; type ChartData = Record & { diff --git a/apps/dashboard/src/components/embedded-wallets/Analytics/Summary.tsx b/apps/dashboard/src/components/embedded-wallets/Analytics/Summary.tsx index 625fdf1c323..176b89d71f5 100644 --- a/apps/dashboard/src/components/embedded-wallets/Analytics/Summary.tsx +++ b/apps/dashboard/src/components/embedded-wallets/Analytics/Summary.tsx @@ -1,6 +1,6 @@ -import type { InAppWalletStats } from "@/api/analytics"; import { Stat } from "components/analytics/stat"; import { ActivityIcon, UserIcon } from "lucide-react"; +import type { InAppWalletStats } from "types/analytics"; export function InAppWalletsSummary(props: { allTimeStats: InAppWalletStats[] | undefined; diff --git a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary.tsx b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary.tsx index 53883ea03ee..4c8b0ca49b0 100644 --- a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary.tsx +++ b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary.tsx @@ -1,6 +1,6 @@ -import type { UserOpStats } from "@/api/analytics"; import { Stat } from "components/analytics/stat"; import { ActivityIcon, CoinsIcon } from "lucide-react"; +import type { UserOpStats } from "types/analytics"; export function AccountAbstractionSummary(props: { aggregateUserOpUsageQuery?: UserOpStats; diff --git a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard.tsx b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard.tsx index 18977314f2f..608d72863c1 100644 --- a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard.tsx +++ b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard.tsx @@ -1,6 +1,5 @@ "use client"; -import type { UserOpStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -24,6 +23,7 @@ import { format } from "date-fns"; import { useAllChainsData } from "hooks/chains/allChains"; import { useMemo } from "react"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import type { UserOpStats } from "types/analytics"; import { formatTickerNumber } from "../../../lib/format-utils"; type ChartData = Record & { diff --git a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/TotalSponsoredChartCard.tsx b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/TotalSponsoredChartCard.tsx index 839aaf4cd52..33d0efa3ad5 100644 --- a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/TotalSponsoredChartCard.tsx +++ b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/TotalSponsoredChartCard.tsx @@ -1,6 +1,5 @@ "use client"; -import type { UserOpStats } from "@/api/analytics"; import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; import { type ChartConfig, @@ -23,6 +22,7 @@ import { DocLink } from "components/shared/DocLink"; import { format } from "date-fns"; import { useMemo } from "react"; import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"; +import type { UserOpStats } from "types/analytics"; import { useAllChainsData } from "../../../hooks/chains/allChains"; import { formatTickerNumber } from "../../../lib/format-utils"; diff --git a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/storyUtils.ts b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/storyUtils.ts index 7983494756f..60654cd8e8b 100644 --- a/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/storyUtils.ts +++ b/apps/dashboard/src/components/smart-wallets/AccountAbstractionAnalytics/storyUtils.ts @@ -1,4 +1,4 @@ -import type { UserOpStats } from "@/api/analytics"; +import type { UserOpStats } from "types/analytics"; export function createUserOpStatsStub(days: number): UserOpStats[] { const stubbedData: UserOpStats[] = []; diff --git a/apps/dashboard/src/data/analytics/wallets/ecosystem.ts b/apps/dashboard/src/data/analytics/wallets/ecosystem.ts index 3800a0cd6f7..7ee299a825d 100644 --- a/apps/dashboard/src/data/analytics/wallets/ecosystem.ts +++ b/apps/dashboard/src/data/analytics/wallets/ecosystem.ts @@ -1,4 +1,4 @@ -import type { EcosystemWalletStats } from "@/api/analytics"; +import type { EcosystemWalletStats } from "types/analytics"; import { fetchAnalytics } from "../fetch-analytics"; export async function getEcosystemWalletUsage(args: { diff --git a/apps/dashboard/src/data/analytics/wallets/in-app.ts b/apps/dashboard/src/data/analytics/wallets/in-app.ts index aeb3c9c226e..a477f04219f 100644 --- a/apps/dashboard/src/data/analytics/wallets/in-app.ts +++ b/apps/dashboard/src/data/analytics/wallets/in-app.ts @@ -1,4 +1,4 @@ -import type { InAppWalletStats } from "@/api/analytics"; +import type { InAppWalletStats } from "types/analytics"; import { fetchAnalytics } from "../fetch-analytics"; export async function getInAppWalletUsage(args: { diff --git a/apps/dashboard/src/types/analytics.ts b/apps/dashboard/src/types/analytics.ts new file mode 100644 index 00000000000..e84c72767d1 --- /dev/null +++ b/apps/dashboard/src/types/analytics.ts @@ -0,0 +1,43 @@ +export interface WalletStats { + date: string; + uniqueWalletsConnected: number; + totalConnections: number; + walletType: string; +} + +export interface WalletUserStats { + date: string; + newUsers: number; + returningUsers: number; + totalUsers: number; +} + +export interface InAppWalletStats { + date: string; + authenticationMethod: string; + uniqueWalletsConnected: number; +} + +export interface EcosystemWalletStats extends InAppWalletStats {} + +export interface UserOpStats { + date: string; + successful: number; + failed: number; + sponsoredUsd: number; + chainId?: string; +} + +export interface RpcMethodStats { + date: string; + evmMethod: string; + count: number; +} + +export interface AnalyticsQueryParams { + clientId?: string; + accountId?: string; + from?: Date; + to?: Date; + period?: "day" | "week" | "month" | "year" | "all"; +}