Skip to content

Commit 2e641f8

Browse files
committed
1 parent c8ad066 commit 2e641f8

File tree

10 files changed

+345
-384
lines changed

10 files changed

+345
-384
lines changed

apps/dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"scripts": {
66
"preinstall": "npx only-allow pnpm",
7-
"dev": "next dev --turbopack",
7+
"dev": "next dev",
88
"build": "NODE_OPTIONS=--max-old-space-size=6144 next build",
99
"start": "next start",
1010
"format": "biome format ./src --write",

apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/UsagePage.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { API_SERVER_URL } from "@/constants/env";
2+
import type { UsageBillableByService } from "@3rdweb-sdk/react/hooks/useApi";
3+
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
4+
5+
export async function getAccountUsage() {
6+
const token = await getAuthToken();
7+
8+
if (!token) {
9+
return undefined;
10+
}
11+
12+
const res = await fetch(`${API_SERVER_URL}/v1/account/usage`, {
13+
method: "GET",
14+
headers: {
15+
"Content-Type": "application/json",
16+
Authorization: `Bearer ${token}`,
17+
},
18+
});
19+
20+
if (!res.ok) {
21+
return undefined;
22+
}
23+
24+
const json = await res.json();
25+
return json.data as UsageBillableByService;
26+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import type { UsageBillableByService } from "@3rdweb-sdk/react/hooks/useApi";
2+
import { useMemo } from "react";
3+
import { toNumber, toPercent, toSize } from "utils/number";
4+
import { UsageCard } from "./UsageCard";
5+
6+
interface UsageProps {
7+
usage: UsageBillableByService;
8+
}
9+
10+
export const Usage: React.FC<UsageProps> = ({ usage: usageData }) => {
11+
const bundlerMetrics = useMemo(() => {
12+
const metric = {
13+
title: "Total sponsored fees",
14+
total: 0,
15+
};
16+
17+
if (!usageData) {
18+
return metric;
19+
}
20+
21+
return {
22+
title: metric.title,
23+
total: usageData.billableUsd.bundler,
24+
};
25+
}, [usageData]);
26+
27+
const storageMetrics = useMemo(() => {
28+
if (!usageData) {
29+
return {};
30+
}
31+
32+
const consumedBytes = usageData.usage.storage.sumFileSizeBytes;
33+
const limitBytes = usageData.limits.storage;
34+
const percent = toPercent(consumedBytes, limitBytes);
35+
36+
return {
37+
total: `${toSize(consumedBytes, "MB")} / ${toSize(
38+
limitBytes,
39+
)} (${percent}%)`,
40+
progress: percent,
41+
...(usageData.billableUsd.storage > 0
42+
? {
43+
overage: usageData.billableUsd.storage,
44+
}
45+
: {}),
46+
};
47+
}, [usageData]);
48+
49+
const walletsMetrics = useMemo(() => {
50+
if (!usageData) {
51+
return {};
52+
}
53+
54+
const numOfWallets = usageData.usage.embeddedWallets.countWalletAddresses;
55+
const limitWallets = usageData.limits.embeddedWallets;
56+
const percent = toPercent(numOfWallets, limitWallets);
57+
58+
return {
59+
total: `${toNumber(numOfWallets)} / ${toNumber(
60+
limitWallets,
61+
)} (${percent}%)`,
62+
progress: percent,
63+
...(usageData.billableUsd.embeddedWallets > 0
64+
? {
65+
overage: usageData.billableUsd.embeddedWallets,
66+
}
67+
: {}),
68+
};
69+
}, [usageData]);
70+
71+
const rpcMetrics = useMemo(() => {
72+
if (!usageData) {
73+
return {};
74+
}
75+
76+
return {
77+
title: "Unlimited requests",
78+
total: (
79+
<span className="text-muted-foreground">
80+
{usageData.rateLimits.rpc} Requests Per Second
81+
</span>
82+
),
83+
};
84+
}, [usageData]);
85+
86+
const gatewayMetrics = useMemo(() => {
87+
if (!usageData) {
88+
return {};
89+
}
90+
91+
return {
92+
title: "Unlimited requests",
93+
total: (
94+
<span className="text-muted-foreground">
95+
{usageData.rateLimits.storage} Requests Per Second
96+
</span>
97+
),
98+
};
99+
}, [usageData]);
100+
101+
return (
102+
<div className="flex grow flex-col gap-12">
103+
<div className="grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3">
104+
<UsageCard
105+
{...rpcMetrics}
106+
name="RPC"
107+
tooltip="RPC usage is calculated by requests per second."
108+
/>
109+
<UsageCard
110+
{...gatewayMetrics}
111+
name="Storage Gateway"
112+
tooltip="Storage gateway usage is calculated by GB per file size."
113+
/>
114+
<UsageCard
115+
{...storageMetrics}
116+
name="Storage Pinning"
117+
tooltip="Storage pinning usage is calculated by GB per file size."
118+
/>
119+
<UsageCard
120+
{...walletsMetrics}
121+
name="Email Wallets"
122+
tooltip="Email wallet (with managed recovery code) usage is calculated by monthly active wallets (i.e. active as defined by at least 1 user log-in via email or social within the billing period month)."
123+
/>
124+
<UsageCard
125+
{...bundlerMetrics}
126+
name="Account Abstraction"
127+
tooltip="(Gasless, Paymaster, Bundler) usage is calculated by sponsored network fees."
128+
/>
129+
</div>
130+
</div>
131+
);
132+
};

apps/dashboard/src/components/settings/Account/UsageCard.tsx renamed to apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/UsageCard.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { ToolTipLabel } from "@/components/ui/tooltip";
22
import { cn } from "@/lib/utils";
33
import { CircleHelpIcon } from "lucide-react";
4-
import { toUSD } from "utils/number";
5-
64
import type { JSX } from "react";
5+
import { toUSD } from "utils/number";
76

87
interface UsageCardProps {
98
name: string;
@@ -23,20 +22,18 @@ export const UsageCard: React.FC<UsageCardProps> = ({
2322
tooltip,
2423
}) => {
2524
return (
26-
<div className="flex min-h-[140px] flex-col rounded-lg border border-border bg-background p-4">
27-
<div className="flex items-center gap-2">
28-
<h3 className="font-medium text-base">{name}</h3>
29-
{tooltip && (
30-
<ToolTipLabel label={tooltip}>
31-
<CircleHelpIcon className="size-4 text-muted-foreground" />
32-
</ToolTipLabel>
33-
)}
34-
</div>
25+
<div className="relative flex min-h-[150px] flex-col rounded-lg border border-border bg-muted/50 p-4">
26+
<h3 className="pr-10 font-medium text-lg">{name}</h3>
27+
{tooltip && (
28+
<ToolTipLabel label={tooltip}>
29+
<CircleHelpIcon className="absolute top-4 right-4 size-5 text-muted-foreground hover:text-foreground" />
30+
</ToolTipLabel>
31+
)}
3532

3633
<div className="h-6" />
3734

38-
<div className="mt-auto flex flex-col gap-2">
39-
{title && <p className="mb-2 font-semibold text-foreground">{title}</p>}
35+
<div className="mt-auto flex flex-col gap-1.5">
36+
{title && <p className="text-foreground text-sm">{title}</p>}
4037

4138
{total !== undefined && (
4239
<p className="text-muted-foreground text-sm">

0 commit comments

Comments
 (0)