Skip to content

Commit 1f60de8

Browse files
MananTankjnsdls
authored andcommitted
Add charts on usage page
1 parent ffc8ed7 commit 1f60de8

File tree

12 files changed

+227
-215
lines changed

12 files changed

+227
-215
lines changed

apps/dashboard/src/app/team/[team_slug]/(team)/_components/TotalSponsoredCard.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import type { UserOpStats } from "@/api/analytics";
2+
import { cn } from "@/lib/utils";
23
import { defineChain } from "thirdweb";
34
import { type ChainMetadata, getChainMetadata } from "thirdweb/chains";
5+
import { EmptyAccountAbstractionChartContent } from "../../../../../components/smart-wallets/AccountAbstractionAnalytics/SponsoredTransactionsChartCard";
6+
import { BarChart } from "../../../components/Analytics/BarChart";
47
import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard";
58

69
export async function TotalSponsoredChartCardUI({
@@ -81,19 +84,33 @@ export async function TotalSponsoredChartCardUI({
8184
},
8285
};
8386

87+
if (onlyMainnet) {
88+
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
89+
return (
90+
<div className={cn("rounded-lg border p-4 lg:p-6", className)}>
91+
<h3 className="mb-1 font-semibold text-xl tracking-tight">
92+
{title || "Total Sponsored"}
93+
</h3>
94+
<p className="text-muted-foreground"> {description}</p>
95+
<BarChart
96+
isCurrency
97+
chartConfig={chartConfig}
98+
data={filteredData}
99+
activeKey="mainnet"
100+
emptyChartContent={<EmptyAccountAbstractionChartContent />}
101+
/>
102+
</div>
103+
);
104+
}
105+
84106
return (
85107
<CombinedBarChartCard
86108
isCurrency
87109
title={title || "Total Sponsored"}
88-
description={description}
89110
chartConfig={chartConfig}
90111
data={timeSeriesData}
91-
hideTabs={onlyMainnet}
92112
activeChart={
93-
onlyMainnet
94-
? "mainnet"
95-
: ((searchParams?.totalSponsored as keyof typeof chartConfig) ??
96-
"mainnet")
113+
(searchParams?.totalSponsored as keyof typeof chartConfig) ?? "mainnet"
97114
}
98115
queryKey="totalSponsored"
99116
existingQueryParams={searchParams}

apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ export function PlanInfoCard(props: {
7575
{isActualFreePlan ? (
7676
<div className="flex flex-col items-center py-8 text-center max-sm:gap-4">
7777
<CircleAlertIcon className="mb-3 text-muted-foreground lg:size-6" />
78-
<p>Your plan includes a fixed amount of free usage</p>
78+
<p>Your plan includes a fixed amount of free usage.</p>
7979
<p>
80-
To unlock additional usage, Upgrade your plan to Starer or Growth
80+
To unlock additional usage, upgrade your plan to Starter or
81+
Growth.
8182
</p>
8283
</div>
8384
) : (
@@ -101,18 +102,10 @@ function BillingInfo({
101102
(subscription) => subscription.type === "USAGE",
102103
);
103104

104-
// only plan and usage subscriptions are considered for now
105-
const totalUsd = getAllSubscriptionsTotal(
106-
subscriptions.filter((sub) => sub.type === "PLAN" || sub.type === "USAGE"),
107-
);
108-
109105
return (
110106
<div>
111107
{planSubscription && (
112-
<SubscriptionOverview
113-
subscription={planSubscription}
114-
title="Plan Cost"
115-
/>
108+
<SubscriptionOverview subscription={planSubscription} />
116109
)}
117110

118111
{usageSubscription && (
@@ -124,28 +117,23 @@ function BillingInfo({
124117
/>
125118
</>
126119
)}
127-
128-
<Separator className="my-4" />
129-
130-
<div className="flex items-center justify-between gap-6">
131-
<h5 className="font-medium text-lg">Total Upcoming Bill</h5>
132-
<p className="text-foreground">{totalUsd}</p>
133-
</div>
134120
</div>
135121
);
136122
}
137123

138124
function SubscriptionOverview(props: {
139125
subscription: TeamSubscription;
140-
title: string;
126+
title?: string;
141127
}) {
142128
const { subscription } = props;
143129

144130
return (
145131
<div>
146132
<div className="flex items-center justify-between gap-6">
147133
<div>
148-
<h5 className="font-medium text-lg">{props.title} </h5>
134+
{props.title && (
135+
<h5 className="font-medium text-lg">{props.title}</h5>
136+
)}
149137
<p className="text-muted-foreground text-sm lg:text-base">
150138
{format(
151139
new Date(props.subscription.currentPeriodStart),
@@ -159,7 +147,7 @@ function SubscriptionOverview(props: {
159147
</p>
160148
</div>
161149

162-
<p className="text-muted-foreground">
150+
<p className="text-foreground">
163151
{formatCurrencyAmount(
164152
subscription.upcomingInvoice.amount || 0,
165153
subscription.upcomingInvoice.currency,
@@ -170,21 +158,6 @@ function SubscriptionOverview(props: {
170158
);
171159
}
172160

173-
function getAllSubscriptionsTotal(subscriptions: TeamSubscription[]) {
174-
let totalCents = 0;
175-
let currency = "USD";
176-
177-
for (const subscription of subscriptions) {
178-
const amount = subscription.upcomingInvoice.amount;
179-
currency = subscription.upcomingInvoice.currency;
180-
if (amount) {
181-
totalCents += amount;
182-
}
183-
}
184-
185-
return formatCurrencyAmount(totalCents, currency);
186-
}
187-
188161
function formatCurrencyAmount(centsAmount: number, currency: string) {
189162
return new Intl.NumberFormat(undefined, {
190163
style: "currency",

apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/Usage.tsx

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import type {
77
UsageBillableByService,
88
} from "@3rdweb-sdk/react/hooks/useApi";
99
import { InAppWalletUsersChartCardUI } from "components/embedded-wallets/Analytics/InAppWalletUsersChartCard";
10+
import { subMonths } from "date-fns";
1011
import Link from "next/link";
1112
import { Suspense, useMemo } from "react";
1213
import { toPercent, toSize } from "utils/number";
1314
import { TotalSponsoredChartCardUI } from "../../../../_components/TotalSponsoredCard";
1415
import { UsageCard } from "./UsageCard";
1516

1617
type UsageProps = {
18+
// TODO - remove when we have all the data available from team
1719
usage: UsageBillableByService;
1820
subscriptions: TeamSubscription[];
1921
account: Account;
@@ -26,6 +28,7 @@ export const Usage: React.FC<UsageProps> = ({
2628
account,
2729
team,
2830
}) => {
31+
// TODO - get this from team instead of account
2932
const storageMetrics = useMemo(() => {
3033
if (!usageData) {
3134
return {};
@@ -36,18 +39,18 @@ export const Usage: React.FC<UsageProps> = ({
3639
const percent = toPercent(consumedBytes, limitBytes);
3740

3841
return {
39-
total: `${toSize(consumedBytes, "MB")} / ${toSize(
40-
limitBytes,
41-
)} (${percent}%)`,
42+
total: `${toSize(Math.min(consumedBytes, limitBytes), "MB")} of ${toSize(limitBytes)} included storage used`,
4243
progress: percent,
4344
...(usageData.billableUsd.storage > 0
4445
? {
4546
overage: usageData.billableUsd.storage,
4647
}
4748
: {}),
49+
totalUsage: `Total Usage: ${toSize(consumedBytes, "MB")}`,
4850
};
4951
}, [usageData]);
5052

53+
// TODO - get this from team instead of account
5154
const rpcMetrics = useMemo(() => {
5255
if (!usageData) {
5356
return {};
@@ -80,23 +83,30 @@ export const Usage: React.FC<UsageProps> = ({
8083

8184
const usageSub = subscriptions.find((sub) => sub.type === "USAGE");
8285

86+
// we don't have `usageSub` for free plan - so we use "1 month ago" as the period
87+
// even free plan can have usage data
88+
89+
const currentPeriodStart = usageSub?.currentPeriodStart
90+
? new Date(usageSub.currentPeriodStart)
91+
: subMonths(new Date(), 1);
92+
93+
const currentPeriodEnd = usageSub?.currentPeriodEnd
94+
? new Date(usageSub.currentPeriodEnd)
95+
: new Date();
96+
8397
return (
8498
<div className="flex grow flex-col gap-8">
85-
{usageSub && (
86-
<>
87-
<InAppWalletUsersChartCard
88-
accountId={account.id}
89-
from={new Date(usageSub.currentPeriodStart)}
90-
to={new Date(usageSub.currentPeriodEnd)}
91-
/>
92-
93-
<TotalSponsoredCard
94-
accountId={account.id}
95-
from={new Date(usageSub.currentPeriodStart)}
96-
to={new Date(usageSub.currentPeriodEnd)}
97-
/>
98-
</>
99-
)}
99+
<InAppWalletUsersChartCard
100+
accountId={account.id}
101+
from={currentPeriodStart}
102+
to={currentPeriodEnd}
103+
/>
104+
105+
<TotalSponsoredCard
106+
accountId={account.id}
107+
from={currentPeriodStart}
108+
to={currentPeriodEnd}
109+
/>
100110

101111
<UsageCard
102112
{...rpcMetrics}

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { cn } from "@/lib/utils";
21
import type { JSX } from "react";
32
import { toUSD } from "utils/number";
43

@@ -10,6 +9,7 @@ interface UsageCardProps {
109
progress?: number;
1110
description: string;
1211
children?: JSX.Element;
12+
totalUsage?: string;
1313
}
1414

1515
export const UsageCard: React.FC<UsageCardProps> = ({
@@ -20,10 +20,11 @@ export const UsageCard: React.FC<UsageCardProps> = ({
2020
progress,
2121
description,
2222
children,
23+
totalUsage,
2324
}) => {
2425
return (
2526
<div className="relative flex min-h-[190px] flex-col rounded-lg border border-border bg-muted/50 p-4 lg:p-6">
26-
<h3 className="mb-1 font-semibold text-xl">{name}</h3>
27+
<h3 className="mb-1 font-semibold text-xl tracking-tight">{name}</h3>
2728
<p className="text-muted-foreground"> {description}</p>
2829

2930
<div className="h-6" />
@@ -32,12 +33,13 @@ export const UsageCard: React.FC<UsageCardProps> = ({
3233
{title && <p className="text-foreground">{title}</p>}
3334

3435
{total !== undefined && (
35-
<p className="text-muted-foreground text-sm">
36+
<p className="text-muted-foreground">
3637
{typeof total === "number" ? toUSD(total) : total}
3738
</p>
3839
)}
3940

4041
{progress !== undefined && <Progress value={progress} />}
42+
{totalUsage && <p className="mt-2 text-foreground">{totalUsage}</p>}
4143

4244
{overage && (
4345
<p className="mt-2 text-muted-foreground text-sm">
@@ -58,14 +60,7 @@ function Progress(props: {
5860
return (
5961
<div className="rounded-full bg-muted">
6062
<div
61-
className={cn(
62-
"h-2 rounded-full",
63-
props.value > 90
64-
? "bg-red-600"
65-
: props.value > 50
66-
? "bg-yellow-600"
67-
: "bg-blue-600",
68-
)}
63+
className={"h-2 rounded-full bg-blue-600"}
6964
style={{
7065
width: `${Math.min(props.value, 100)}%`,
7166
}}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default async function Page(props: {
4040

4141
return (
4242
<Usage
43+
// TODO - remove accountUsage when we have all the data available from team
4344
usage={accountUsage}
4445
subscriptions={subscriptions}
4546
account={account}

0 commit comments

Comments
 (0)