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 deleted file mode 100644 index 5290797c0fd..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/ConnectAnalyticsDashboardUI.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { Button } from "@/components/ui/button"; -import type { Range } from "components/analytics/date-range-selector"; -import { Stat } from "components/analytics/stat"; -import { InAppWalletsSummary } from "components/embedded-wallets/Analytics/Summary"; -import { AccountAbstractionSummary } from "components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary"; -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"; -import { WalletConnectorsChartCard } from "./_components/WalletConnectorsChartCard"; -import { WalletDistributionChartCard } from "./_components/WalletDistributionChartCard"; - -export function ConnectAnalyticsDashboardUI(props: { - walletUsage: WalletStats[]; - aggregateWalletUsage: WalletStats[]; - aggregateUserOpUsageQuery?: UserOpStats; - connectLayoutSlug: string; - isPending: boolean; - inAppAggregateQuery?: { - allTimeStats: InAppWalletStats[]; - monthlyStats: InAppWalletStats[]; - }; - setRange: (range: Range) => void; - range: Range; - intervalType: "day" | "week"; - setIntervalType: (intervalType: "day" | "week") => void; -}) { - const { totalWallets, uniqueWallets } = useMemo(() => { - return props.aggregateWalletUsage.reduce( - (acc, curr) => { - acc.totalWallets += curr.totalConnections; - acc.uniqueWallets += curr.uniqueWalletsConnected; - return acc; - }, - { uniqueWallets: 0, totalWallets: 0 }, - ); - }, [props.aggregateWalletUsage]); - - return ( -
-
-
-
-

- Connections -

-

- View how many users are connecting to your app. -

-
-
-
- - -
-
- -
-
-
- -
-
-
-

- In-App Wallets -

-

- View metrics for your in-app wallets. -

-
- -
- -
-
- -
- -
-
-
- -
-
-
-

- Account Abstraction -

-

- View how smart wallets are used in your app. -

-
- -
- -
-
- -
- -
-
-
- -
- { - props.setRange(newRange); - const days = differenceInDays(newRange.to, newRange.from); - props.setIntervalType(days > 30 ? "week" : "day"); - }} - /> - -
- - - - - - -
- ); -} 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 deleted file mode 100644 index f0cc2670f9d..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/ConnectAnalyticsDashboard.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { createUserOpStatsStub } from "components/smart-wallets/AccountAbstractionAnalytics/storyUtils"; -import { getLastNDaysRange } from "../../../../../../../components/analytics/date-range-selector"; -import { mobileViewport } from "../../../../../../../stories/utils"; -import { ConnectAnalyticsDashboardUI } from "../ConnectAnalyticsDashboardUI"; -import { createWalletStatsStub } from "./storyUtils"; - -const meta = { - title: "Charts/Connect/Analytics Dashboard", - component: Component, - parameters: { - layout: "centered", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Desktop: Story = { - args: {}, -}; - -export const Mobile: Story = { - args: {}, - parameters: { - viewport: mobileViewport("iphone14"), - }, -}; - -function Component() { - return ( -
- {}} - range={getLastNDaysRange("last-120")} - intervalType="day" - setIntervalType={() => {}} - walletUsage={createWalletStatsStub(30)} - aggregateWalletUsage={createWalletStatsStub(30)} - aggregateUserOpUsageQuery={createUserOpStatsStub(1)?.[0]} - connectLayoutSlug="connectLayoutSlug" - isPending={false} - /> -
- ); -} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.stories.tsx deleted file mode 100644 index b416e9015d6..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.stories.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { - BadgeContainer, - mobileViewport, -} from "../../../../../../../stories/utils"; -import { DailyConnectionsChartCard } from "./DailyConnectionsChartCard"; -import { createWalletStatsStub } from "./storyUtils"; - -const meta = { - title: "Charts/Connect/Daily Connections", - component: Component, - parameters: { - layout: "centered", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Desktop: Story = { - args: {}, -}; - -export const Mobile: Story = { - args: {}, - parameters: { - viewport: mobileViewport("iphone14"), - }, -}; - -function Component() { - return ( -
- - - - - - - - - - - - - - - - - - - -
- ); -} 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 deleted file mode 100644 index ea9f3b1f749..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/DailyConnectionsChartCard.tsx +++ /dev/null @@ -1,243 +0,0 @@ -"use client"; - -import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; -import { - type ChartConfig, - ChartContainer, - ChartTooltip, - ChartTooltipContent, -} from "@/components/ui/chart"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { - EmptyChartState, - LoadingChartState, -} from "components/analytics/empty-chart-state"; -import { DotNetIcon } from "components/icons/brand-icons/DotNetIcon"; -import { ReactIcon } from "components/icons/brand-icons/ReactIcon"; -import { TypeScriptIcon } from "components/icons/brand-icons/TypeScriptIcon"; -import { UnityIcon } from "components/icons/brand-icons/UnityIcon"; -import { UnrealIcon } from "components/icons/brand-icons/UnrealIcon"; -import { DocLink } from "components/shared/DocLink"; -import { format } from "date-fns"; -import { useMemo, useState } from "react"; -import { - Bar, - BarChart, - CartesianGrid, - LabelList, - XAxis, - YAxis, -} from "recharts"; -import type { WalletStats } from "types/analytics"; -import { formatTickerNumber } from "../../../../../../../lib/format-utils"; - -type ChartToShow = "uniqueWallets" | "totalWallets"; - -type ChartData = { - time: string; // human readable date - totalWallets: number; - uniqueWallets: number; -}; - -const chartConfig = { - uniqueWallets: { - label: "Unique Wallets", - color: "hsl(var(--chart-1))", - }, - totalWallets: { - label: "Total Wallets", - color: "hsl(var(--chart-1))", - }, -} satisfies ChartConfig; - -const chartLabelToShow: Record = { - uniqueWallets: "Unique Wallets", - totalWallets: "Total Wallets", -}; - -export function DailyConnectionsChartCard(props: { - walletStats: WalletStats[]; - isPending: boolean; -}) { - const { walletStats } = props; - - const [chartToShow, setChartToShow] = useState("uniqueWallets"); - const chartToShowOptions: ChartToShow[] = ["uniqueWallets", "totalWallets"]; - - const barChartData: ChartData[] = useMemo(() => { - const chartDataMap: Map = new Map(); - - for (const data of walletStats) { - const chartData = chartDataMap.get(data.date); - if (!chartData) { - chartDataMap.set(data.date, { - time: format(new Date(data.date), "MMM dd"), - totalWallets: data.totalConnections, - uniqueWallets: data.uniqueWalletsConnected, - }); - } else { - chartData.totalWallets += data.totalConnections; - chartData.uniqueWallets += data.uniqueWalletsConnected; - } - } - - return Array.from(chartDataMap.values()); - }, [walletStats]); - - const disableActions = props.isPending || barChartData.length === 0; - - return ( -
-

- Daily Connections -

-

- Total and unique wallets addresses that connected to your app each day. -

- -
- {/* Selector */} - - - { - const header = ["Date", "Total Wallets", "Unique Wallets"]; - const rows = barChartData.map((row) => [ - row.time, - row.totalWallets.toString(), - row.uniqueWallets.toString(), - ]); - return { header, rows }; - }} - fileName="DailyConnections" - /> -
- - {/* Chart */} - - {props.isPending ? ( - - ) : barChartData.length === 0 ? ( - -
- - Send your first connect event - -
- - - - - - -
-
-
- ) : ( - - - - - - data[chartToShow]} - tickLine={false} - axisLine={false} - tickFormatter={(value) => formatTickerNumber(value)} - /> - - formatTickerNumber(Number(value))} - /> - } - /> - - - {barChartData.length < 50 && ( - formatTickerNumber(value)} - /> - )} - - - )} -
-
- ); -} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.stories.tsx deleted file mode 100644 index cf3e3cc8fc8..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.stories.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { - BadgeContainer, - mobileViewport, -} from "../../../../../../../stories/utils"; -import { WalletConnectorsChartCard } from "./WalletConnectorsChartCard"; -import { createWalletStatsStub } from "./storyUtils"; - -const meta = { - title: "Charts/Connect/Wallet Connectors", - component: Component, - parameters: { - layout: "centered", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Desktop: Story = { - args: {}, -}; - -export const Mobile: Story = { - args: {}, - parameters: { - viewport: mobileViewport("iphone14"), - }, -}; - -function Component() { - return ( -
- - - - - - - - - - - - - - - - - - - -
- ); -} 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 deleted file mode 100644 index 087c842ac1e..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletConnectorsChartCard.tsx +++ /dev/null @@ -1,260 +0,0 @@ -"use client"; - -import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; -import { - type ChartConfig, - ChartContainer, - ChartLegend, - ChartLegendContent, - ChartTooltip, - ChartTooltipContent, -} from "@/components/ui/chart"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { - EmptyChartState, - LoadingChartState, -} from "components/analytics/empty-chart-state"; -import { ReactIcon } from "components/icons/brand-icons/ReactIcon"; -import { TypeScriptIcon } from "components/icons/brand-icons/TypeScriptIcon"; -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, -} from "../../../../../../../lib/format-utils"; - -type ChartToShow = "uniqueWalletsConnected" | "totalConnections"; - -type ChartData = Record & { - time: string; // human readable date -}; - -const chartLabelToShow: Record = { - uniqueWalletsConnected: "Unique Wallets", - totalConnections: "Total Wallets", -}; -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( - "uniqueWalletsConnected", - ); - const chartToShowOptions: ChartToShow[] = [ - "uniqueWalletsConnected", - "totalConnections", - ]; - - const { chartConfig, chartData } = useMemo(() => { - const _chartConfig: ChartConfig = {}; - const _chartDataMap: Map = new Map(); - 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: rawWalletType } = stat; - const walletType = formatWalletType(rawWalletType); - - // if no data for current day - create new entry - if (!chartData) { - _chartDataMap.set(stat.date, { - time: format(new Date(stat.date), "MMM dd"), - [walletType]: stat[chartToShow], - } as ChartData); - } else { - chartData[walletType] = - (chartData[walletType] || 0) + stat[chartToShow]; - } - - walletTypeToValueMap.set( - walletType, - stat[chartToShow] + (walletTypeToValueMap.get(walletType) || 0), - ); - } - - const walletTypesSorted = Array.from(walletTypeToValueMap.entries()) - .sort((a, b) => b[1] - a[1]) - .map((w) => w[0]); - - 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: 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()), - chartConfig: _chartConfig, - }; - }, [walletStats, chartToShow]); - - const uniqueWalletTypes = Object.keys(chartConfig); - const disableActions = props.isPending || chartData.length === 0; - - return ( -
-

- Connected Wallets -

-

- The different types of wallets used to connect to your app each day. -

- -
- - - { - // Shows the number of each type of wallet connected on all dates - const header = ["Date", ...uniqueWalletTypes]; - const rows = chartData.map((data) => { - const { time, ...rest } = data; - return [ - time, - ...uniqueWalletTypes.map((w) => (rest[w] || 0).toString()), - ]; - }); - return { header, rows }; - }} - /> -
- - {/* Chart */} - - {props.isPending ? ( - - ) : chartData.length === 0 ? ( - -
- - Connect any wallet to your app - -
- - - -
-
-
- ) : ( - - - - - - - Object.entries(data) - .filter(([key]) => key !== "time") - .map(([, value]) => value) - .reduce((acc, current) => Number(acc) + Number(current), 0) - } - tickLine={false} - axisLine={false} - tickFormatter={(value) => formatTickerNumber(value)} - /> - - formatTickerNumber(Number(value))} - /> - } - /> - } /> - {uniqueWalletTypes.map((walletType) => { - return ( - - ); - })} - - )} -
-
- ); -} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.stories.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.stories.tsx deleted file mode 100644 index 1cd73663c4f..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.stories.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { - BadgeContainer, - mobileViewport, -} from "../../../../../../../stories/utils"; -import { WalletDistributionChartCard } from "./WalletDistributionChartCard"; -import { createWalletStatsStub } from "./storyUtils"; - -const meta = { - title: "Charts/Connect/Wallet Distribution", - component: Component, - parameters: { - layout: "centered", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Desktop: Story = { - args: {}, -}; - -export const Mobile: Story = { - args: {}, - parameters: { - viewport: mobileViewport("iphone14"), - }, -}; - -function Component() { - return ( -
- - - - - - - - - - - - - - - - - - - -
- ); -} 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 deleted file mode 100644 index 081b254c8df..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/WalletDistributionChartCard.tsx +++ /dev/null @@ -1,263 +0,0 @@ -"use client"; - -import { ExportToCSVButton } from "@/components/blocks/ExportToCSVButton"; -import { - type ChartConfig, - ChartContainer, - ChartLegend, - ChartLegendContent, - ChartTooltip, - ChartTooltipContent, -} from "@/components/ui/chart"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { - EmptyChartState, - LoadingChartState, -} from "components/analytics/empty-chart-state"; -import { ReactIcon } from "components/icons/brand-icons/ReactIcon"; -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, -} from "../../../../../../../lib/format-utils"; - -type ChartToShow = "totalConnections" | "uniqueWalletsConnected"; - -type ChartData = { - walletType: string; - value: number; - fill: string; -}; - -const chartLabelToShow: Record = { - 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("totalConnections"); - const chartToShowOptions: ChartToShow[] = [ - "totalConnections", - "uniqueWalletsConnected", - ]; - - const { chartConfig, chartData, totalConnections, uniqueConnections } = - useMemo(() => { - const _chartDataMap: Map = new Map(); - const walletTypeToValueMap: Map = new Map(); - - let _totalConnections = 0; - let _uniqueConnections = 0; - - for (const stat of walletStats) { - const { walletType: rawWalletType } = stat; - const walletType = formatWalletType(rawWalletType); - 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], - ); - } - - const walletTypesSortedByValue = Array.from( - walletTypeToValueMap.entries(), - ) - .sort((a, b) => b[1] - a[1]) - .map((w) => w[0]); - - const walletTypesToShow = walletTypesSortedByValue.slice( - 0, - topWalletsToShow, - ); - - const walletTypesToTagAsOthers = - walletTypesSortedByValue.slice(topWalletsToShow); - - 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: 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, - value: data, - fill: _chartConfig[walletType]?.color || "transparent", - }; - }, - ); - - // sort the data - _chartData.sort((a, b) => b.value - a.value); - - return { - chartData: _chartData, - chartConfig: _chartConfig, - totalConnections: _totalConnections, - uniqueConnections: _uniqueConnections, - }; - }, [walletStats, chartToShow]); - - const disableActions = props.isPending || chartData.length === 0; - return ( -
-

- Wallet Distribution -

-

- Distribution of wallet types used to connect to your app. -

- - {/* Selector */} -
- - - { - const header = [ - "Wallet", - `${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`, - `Percentage of ${chartToShow === "totalConnections" ? "Total" : "Unique"} Connections`, - ]; - const rows = chartData.map((d) => { - return [ - d.walletType, - d.value.toString(), - `${((d.value / (chartToShow === "totalConnections" ? totalConnections : uniqueConnections)) * 100).toFixed(2)}%`, - ]; - }); - return { - header, - rows, - }; - }} - /> -
- - {/* Chart */} - - {props.isPending ? ( - - ) : chartData.length === 0 ? ( - -
- - Connect any wallet to your app - -
- - - -
-
-
- ) : ( - - { - if (typeof v === "number") { - const sumValue = - chartToShow === "uniqueWalletsConnected" - ? uniqueConnections - : totalConnections; - const percentageValue = ((v / sumValue) * 100).toFixed(2); - return `${percentageValue}% - ${formatTickerNumber(v)}`; - } - }} - /> - } - /> - } className="" /> - - - )} -
-
- ); -} 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 deleted file mode 100644 index bb64da83daf..00000000000 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/analytics/_components/storyUtils.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { WalletId } from "thirdweb/wallets"; -import type { WalletStats } from "types/analytics"; - -const walletsToPickFrom: WalletId[] = [ - "io.metamask", - "com.binance", - "com.coinbase.wallet", - "io.zerion.wallet", - "me.rainbow", - "com.trustwallet.app", - "com.zengo", - "xyz.argent", - "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 = () => { - return ( - walletsToPickFrom[Math.floor(Math.random() * walletsToPickFrom.length)] || - "io.metamask" - ); -}; - -export function createWalletStatsStub(days: number): WalletStats[] { - const stubbedData: WalletStats[] = []; - - let d = days; - while (d !== 0) { - const uniqueWallets = Math.floor(Math.random() * 100); - stubbedData.push({ - date: new Date(2024, 1, d).toLocaleString(), - totalConnections: uniqueWallets + Math.floor(Math.random() * 100), - uniqueWalletsConnected: uniqueWallets, - walletType: pickRandomWallet(), - }); - - if (Math.random() > 0.7) { - d--; - } - } - - return stubbedData; -} diff --git a/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx b/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx index 41ec77f948d..ab30f5b952d 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/CouponCard.tsx @@ -16,7 +16,6 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useMutation, useQuery } from "@tanstack/react-query"; import { format, fromUnixTime } from "date-fns"; import { TagIcon } from "lucide-react"; -import dynamic from "next/dynamic"; import { useSearchParams } from "next/navigation"; import { Suspense, useEffect, useRef, useState } from "react"; import { useForm } from "react-hook-form"; @@ -24,17 +23,6 @@ import { toast } from "sonner"; import { useActiveAccount } from "thirdweb/react"; import { z } from "zod"; -const LazyShareFreeWalletsModal = dynamic( - () => - import("./share-free-wallets-modal.client").then((mod) => ({ - default: mod.ShareFreeWalletsModal, - })), - { - ssr: false, - loading: () => null, - }, -); - export type ActiveCouponResponse = { id: string; start: number; @@ -49,10 +37,7 @@ export type ActiveCouponResponse = { function ApplyCouponCard(props: { teamId: string | undefined; - onCouponApplied: ( - data: ActiveCouponResponse, - isFreeWalletsCoupon: boolean, - ) => void; + onCouponApplied: (data: ActiveCouponResponse) => void; isPaymentSetup: boolean; }) { const searchParams = useSearchParams(); @@ -102,9 +87,7 @@ export function ApplyCouponCardUI(props: { status: number; data: null | ActiveCouponResponse; }>; - onCouponApplied: - | ((data: ActiveCouponResponse, isFreeWalletsCoupon: boolean) => void) - | undefined; + onCouponApplied: ((data: ActiveCouponResponse) => void) | undefined; prefillPromoCode?: string; scrollIntoView?: boolean; isPaymentSetup: boolean; @@ -145,14 +128,7 @@ export function ApplyCouponCardUI(props: { case 200: { toast.success("Coupon applied successfully"); if (res.data) { - props.onCouponApplied?.( - res.data, - // prod & dev - values.promoCode === "FREEWALLETS" || - // new prod code - values.promoCode === "FREEWALLETS24" || - values.promoCode === "TESTFREEWALLETS", - ); + props.onCouponApplied?.(res.data); } break; } @@ -284,7 +260,6 @@ export function CouponSection(props: { isPaymentSetup: boolean; }) { const address = useActiveAccount()?.address; - const [showShareModal, setShowShareModal] = useState(false); const [optimisticCouponData, setOptimisticCouponData] = useState< | { type: "added"; @@ -358,15 +333,12 @@ export function CouponSection(props: { }> { + onCouponApplied={(coupon) => { setOptimisticCouponData({ type: "added", data: coupon, }); - if (isFreeWalletsCoupon) { - setShowShareModal(true); - } activeCoupon.refetch().then(() => { setOptimisticCouponData(undefined); }); @@ -375,13 +347,6 @@ export function CouponSection(props: { /> )} - - {showShareModal && ( - - )} ); } diff --git a/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.client.tsx b/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.client.tsx deleted file mode 100644 index 4b886a8093e..00000000000 --- a/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.client.tsx +++ /dev/null @@ -1,401 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { TrackedLinkTW } from "@/components/ui/tracked-link"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { ChevronLeftIcon, MailIcon } from "lucide-react"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { DynamicHeight } from "../../../../@/components/ui/DynamicHeight"; -import { XIcon } from "../../../icons/brand-icons/XIcon"; - -export function ShareFreeWalletsModal(props: { - isOpen: boolean; - onOpenChange: (open: boolean) => void; -}) { - const [screen, setScreen] = useState<"base" | "email">("base"); - - return ( - - - - {screen === "base" && ( -
- -
- -
- - Congratulations! - - - You are getting free wallets for the next 12 months - -
-
- - -
-
- )} - - {screen === "email" && ( - setScreen("base")} /> - )} -
-
-
- ); -} - -const emailFormSchema = z.object({ - email: z.string().email(), - app: z.string(), -}); - -function SendEmailScreen(props: { - goBack: () => void; -}) { - const form = useForm>({ - resolver: zodResolver(emailFormSchema), - defaultValues: { - email: "", - app: "default", - }, - }); - - return ( -
-
- {})}> -
- -
- -
- - Share via Email - - - Give the gift of unlimited wallets to another dev - -
- -
- - ( - - Email - - - - - - - )} - /> - -
- - ( - - Share with - - - - - )} - /> -
- -
- - - {!form.formState.isValid ? ( - - ) : ( - - )} -
- - -
- ); -} - -function openDefaultEmailApp(email: string) { - return `mailto:${email}?subject=${encodeURIComponent(emailSubject)}&body=${encodeURIComponent(emailPostBody)}`; -} - -function openGmailEmailApp(email: string) { - return `https://mail.google.com/mail/?view=cm&fs=1&to=${email}&su=${encodeURIComponent(emailSubject)}&body=${encodeURIComponent(emailPostBody)}`; -} - -const twitterPostBody = `\ -Just claimed the free, unlimited wallets offer from @thirdweb! 🚀 - -No more per-wallet pricing, full support for web, mobile, and console. - -Here's to building without constraints ✨ - -👉 https://thirdweb.com/unlimited-wallets 👈`; - -const emailSubject = "You've unlocked Unlimited Wallets!"; - -const emailPostBody = `\ -Hey there, - -I just came across something that might interest you. thirdweb is offering free, unlimited wallets for developers. -I've claimed it and thought you might want to take a look too. - -Here's the lowdown: -* It's completely free -* No more per-wallet pricing constraints -* Full support for web, mobile, and console development - -I'm pretty excited about the possibilities this opens up for building without limitations. You can check it out here: https://thirdweb.com/unlimited-wallets - -Let me know what you think if you decide to give it a try!`; - -function VibrantSmileIcon(props: { - className?: string; -}) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} - -function VibrantEmailIcon(props: { - className?: string; -}) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.stories.tsx b/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.stories.tsx deleted file mode 100644 index 7c28898006e..00000000000 --- a/apps/dashboard/src/components/settings/Account/Billing/share-free-wallets-modal.stories.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Button } from "@/components/ui/button"; -import type { Meta, StoryObj } from "@storybook/react"; -import { useState } from "react"; -import { mobileViewport } from "../../../../stories/utils"; -import { ShareFreeWalletsModal } from "./share-free-wallets-modal.client"; - -const meta = { - title: "Billing/Coupons/ShareFreeWalletsModal", - component: Variants, - parameters: { - layout: "centered", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Desktop: Story = { - args: {}, -}; - -export const Mobile: Story = { - args: {}, - parameters: { - viewport: mobileViewport("iphone14"), - }, -}; - -function Variants() { - const [isOpen, setIsOpen] = useState(true); - return ( -
- - -
- ); -} diff --git a/apps/dashboard/src/lib/format-utils.ts b/apps/dashboard/src/lib/format-utils.ts index 175caf2ca39..3eaee45ff79 100644 --- a/apps/dashboard/src/lib/format-utils.ts +++ b/apps/dashboard/src/lib/format-utils.ts @@ -5,14 +5,3 @@ const compactNumberFormatter = new Intl.NumberFormat("en-US", { export const formatTickerNumber = (value: number) => { return compactNumberFormatter.format(value); }; - -export const formatWalletType = (walletType: string) => { - return walletType.toLowerCase().includes("inapp") || - walletType.toLowerCase().includes("embedded") - ? "in-app" - : walletType.toLowerCase().includes("metamask") - ? "metamask" - : walletType.toLowerCase().includes("coinbase") - ? "coinbase" - : walletType.toLowerCase(); -};