Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ export async function TotalSponsoredChartCardUI({
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
return (
<div className={cn("rounded-lg border p-4 lg:p-6", className)}>
<h3 className="mb-1 font-semibold text-xl tracking-tight">
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">
{title || "Total Sponsored"}
</h3>
<p className="text-muted-foreground"> {description}</p>
<p className="text-muted-foreground text-sm"> {description}</p>
<BarChart
isCurrency
chartConfig={chartConfig}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { BillingPortalButton } from "@/components/billing";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { TrackedLinkTW } from "@/components/ui/tracked-link";
import { differenceInDays, isAfter } from "date-fns";
import { format } from "date-fns/format";
import { CircleAlertIcon } from "lucide-react";
Expand Down Expand Up @@ -37,7 +36,7 @@ export function PlanInfoCard(props: {
<div className="rounded-lg border border-border bg-card">
<div className="flex flex-col gap-4 p-4 lg:flex-row lg:items-center lg:justify-between lg:p-6">
<div>
<div className="flex flex-col items-start gap-1">
<div className="flex flex-col items-start gap-0.5">
<h3 className="font-semibold text-2xl capitalize tracking-tight">
{validPlan} Plan
</h3>
Expand All @@ -56,6 +55,7 @@ export function PlanInfoCard(props: {

<div className="flex flex-row items-center gap-2">
{/* go to invoices page */}

<Button asChild variant="outline">
<Link href={`/team/${team.slug}/~/settings/invoices`}>
View Invoices
Expand All @@ -73,20 +73,6 @@ export function PlanInfoCard(props: {
>
Manage Billing
</BillingPortalButton>

{isActualFreePlan && (
<Button asChild variant="outline">
<TrackedLinkTW
category="account"
href="/pricing"
label="pricing-plans"
target="_blank"
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground"
>
View Pricing
</TrackedLinkTW>
</Button>
)}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function SponsoredTransactionsTableUI(
<div className="overflow-hidden rounded-lg border bg-card">
{/* header */}
<div className="flex flex-col justify-between gap-3 border-b px-4 py-4 lg:flex-row lg:items-center lg:px-6">
<h2 className="font-semibold text-lg">Sponsored Transactions</h2>
<h2 className="font-semibold text-xl">Sponsored Transactions</h2>
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
{/* Filters */}
<div className="flex gap-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export const UsageCard: React.FC<UsageCardProps> = ({
totalUsage,
}) => {
return (
<div className="relative flex min-h-[190px] flex-col rounded-lg border border-border bg-card p-4 lg:p-6">
<h3 className="mb-1 font-semibold text-xl tracking-tight">{name}</h3>
<p className="text-muted-foreground"> {description}</p>
<div className="relative flex flex-col rounded-lg border border-border bg-card p-4 lg:p-6">
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">{name}</h3>
<p className="text-muted-foreground text-sm"> {description}</p>

<div className="h-6" />

<div className="mt-auto flex flex-col gap-1.5">
<div className="flex flex-col gap-1 text-sm">
{title && <p className="text-foreground">{title}</p>}

{total !== undefined && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ function FooterCard(props: {
trackingCategory: string;
}) {
return (
<div className="rounded-lg border border-border bg-card p-4 lg:p-6">
<h3 className="mb-5 font-semibold text-lg tracking-tight lg:text-xl">
<div className="rounded-lg border border-border bg-card p-4">
<h3 className="mb-4 border-border border-b pt-1 pb-4 font-semibold text-lg leading-none tracking-tight">
{props.title}
</h3>

<div className="flex flex-col gap-2">
<div className="flex flex-col gap-2.5">
{props.links.map((link) => (
<TrackedLinkTW
key={link.href}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,54 @@
"use client";

import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { TabPathLinks } from "@/components/ui/tabs";
import { TrackedUnderlineLink } from "@/components/ui/tracked-link";
import {
TrackedLinkTW,
TrackedUnderlineLink,
} from "@/components/ui/tracked-link";
import { SmartWalletsBillingAlert } from "components/settings/ApiKeys/Alerts";
import { CircleAlertIcon } from "lucide-react";
import { useActiveWalletChain } from "thirdweb/react";
import type { UserOpStats } from "types/analytics";
import { AccountAbstractionSummary } from "../../../../../../components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary";
import { useLocalStorage } from "hooks/useLocalStorage";
import { ArrowRightIcon } from "lucide-react";
import { XIcon } from "lucide-react";
import { AAFooterSection } from "./AAFooterSection";
import { isOpChainId } from "./isOpChain";

const TRACKING_CATEGORY = "smart-wallet";

export function AccountAbstractionLayout(props: {
projectSlug: string;
projectId: string;
teamSlug: string;
projectKey: string;
children: React.ReactNode;
hasSmartWalletsWithoutBilling: boolean;
userOpStats: UserOpStats;
}) {
const chain = useActiveWalletChain();

const isOpChain = chain?.id ? isOpChainId(chain.id) : false;

const smartWalletsLayoutSlug = `/team/${props.teamSlug}/${props.projectSlug}/connect/account-abstraction`;

return (
<div>
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:mb-2 lg:text-3xl">
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:text-3xl">
Account Abstraction
</h1>
<p className="text-muted-foreground text-sm">
Easily integrate Account abstraction (ERC-4337) compliant smart accounts
into your apps.{" "}
Integrate ERC-4337 compliant smart accounts for gasless sponsorships and
more. <br className="lg:hidden" />
<TrackedUnderlineLink
target="_blank"
label="docs-wallets"
category={TRACKING_CATEGORY}
href="https://portal.thirdweb.com/wallets/smart-wallet"
>
View Documentation
Learn more about Account Abstraction
</TrackedUnderlineLink>
</p>

<div className="h-6" />

<div className="flex flex-col gap-6">
{props.hasSmartWalletsWithoutBilling ? (
<SmartWalletsBillingAlert />
) : (
isOpChain && (
<Alert variant="info">
<CircleAlertIcon className="size-4" />
<AlertTitle>
Using the gas credits for OP chain paymaster
</AlertTitle>
<AlertDescription>
Credits will automatically be applied to cover gas fees for any
onchain activity across thirdweb services. <br />
Eligible chains: OP Mainnet, Base, Zora, Frax, Mode.
</AlertDescription>
</Alert>
)
)}
{props.hasSmartWalletsWithoutBilling && <SmartWalletsBillingAlert />}
<GasCreditAlert teamSlug={props.teamSlug} projectId={props.projectId} />

<div>
<AccountAbstractionSummary
aggregateUserOpUsageQuery={props.userOpStats}
/>

<div className="h-12" />
<TabPathLinks
links={[
{
Expand All @@ -93,8 +72,64 @@ export function AccountAbstractionLayout(props: {
{props.children}
</div>
</div>

<div className="h-14" />

<AAFooterSection trackingCategory={TRACKING_CATEGORY} />
</div>
);
}

function GasCreditAlert(props: {
teamSlug: string;
projectId: string;
}) {
const [isVisible, setIsVisible] = useLocalStorage(
`gas-credit-${props.projectId}`,
true,
false,
);

if (!isVisible) return null;

return (
<div className="relative rounded-lg border border-border bg-card p-4">
<Button
onClick={() => setIsVisible(false)}
className="absolute top-4 right-4 h-auto w-auto p-1 text-muted-foreground"
aria-label="Close alert"
variant="ghost"
>
<XIcon className="size-5" />
</Button>
<div>
<h2 className="mb-0.5 font-semibold">OP Gas Credit Program</h2>
<p className="text-muted-foreground text-sm">
Redeem credits towards gas Sponsorship. <br className="lg:hidden" />
<TrackedUnderlineLink
target="_blank"
label="superchain-landing"
category={TRACKING_CATEGORY}
href="https://thirdweb.com/grant/superchain"
>
Learn More
</TrackedUnderlineLink>
</p>

<div className="mt-4 flex items-center gap-4">
<Button asChild variant="outline" size="sm" className="bg-background">
<TrackedLinkTW
href={`/team/${props.teamSlug}/~/settings/credits`}
target="_blank"
className="gap-2"
category={TRACKING_CATEGORY}
label="claim-credits"
>
Claim your credits <ArrowRightIcon className="size-4" />
</TrackedLinkTW>
</Button>
</div>
</div>
</div>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getAggregateUserOpUsage } from "@/api/analytics";
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import type { Metadata } from "next";
Expand Down Expand Up @@ -34,18 +33,13 @@ export default async function Page(props: {
team.billingStatus !== "validPayment" &&
team.billingStatus !== "pastDue";

const userOpStats = await getAggregateUserOpUsage({
teamId: team.id,
projectId: project.id,
});

return (
<AccountAbstractionLayout
userOpStats={userOpStats}
projectSlug={project.slug}
teamSlug={team_slug}
projectKey={project.publishableKey}
hasSmartWalletsWithoutBilling={hasSmartWalletsWithoutBilling}
projectId={project.id}
>
{props.children}
</AccountAbstractionLayout>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getUserOpUsage } from "@/api/analytics";
import { getAggregateUserOpUsage, getUserOpUsage } from "@/api/analytics";
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import {
type Range,
Expand Down Expand Up @@ -31,7 +32,14 @@ export default async function Page(props: {
notFound();
}

const project = await getProject(params.team_slug, params.project_slug);
const [team, project] = await Promise.all([
getTeamBySlug(params.team_slug),
getProject(params.team_slug, params.project_slug),
]);

if (!team) {
redirect("/team");
}

if (!project) {
redirect(`/team/${params.team_slug}`);
Expand All @@ -52,21 +60,32 @@ export default async function Page(props: {
type: rangeType,
};

const userOpStats = await getUserOpUsage({
const userOpStatsPromise = getUserOpUsage({
teamId: project.teamId,
projectId: project.id,
from: range.from,
to: range.to,
period: interval,
});

const aggregateUserOpStatsPromise = getAggregateUserOpUsage({
teamId: team.id,
projectId: project.id,
});

const [userOpStats, aggregateUserOpStats] = await Promise.all([
userOpStatsPromise,
aggregateUserOpStatsPromise,
]);

return (
<AccountAbstractionAnalytics
userOpStats={userOpStats}
client={getThirdwebClient(authToken)}
teamId={project.teamId}
projectId={project.id}
teamSlug={params.team_slug}
aggregateUserOpStats={aggregateUserOpStats}
/>
);
}
10 changes: 4 additions & 6 deletions apps/dashboard/src/components/analytics/stat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ export const Stat: React.FC<{
formatter?: (value: number) => string;
}> = ({ label, value, formatter, icon: Icon }) => {
return (
<dl className="flex items-center justify-between gap-4 rounded-lg border border-border bg-card p-4 lg:p-6">
<dl className="flex items-center justify-between gap-4 rounded-lg border border-border bg-card p-4 pr-6">
<div>
<dd className="font-semibold text-3xl tracking-tight lg:text-5xl">
<dd className="mb-0.5 font-semibold text-2xl tracking-tight">
{value !== undefined && formatter
? formatter(value)
: value?.toLocaleString()}
</dd>
<dt className="font-medium text-muted-foreground text-sm tracking-tight lg:text-lg">
{label}
</dt>
<dt className="text-muted-foreground text-sm">{label}</dt>
</div>
<Icon className="hidden size-12 text-muted-foreground opacity-50 lg:block" />
<Icon className="hidden size-8 text-muted-foreground opacity-50 lg:block" />
</dl>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ export function InAppWalletUsersChartCardUI(props: {

return (
<div className="relative w-full rounded-lg border border-border bg-card p-4 md:p-6">
<h3 className="mb-1 font-semibold text-xl tracking-tight">
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">
{props.title}
</h3>
<p className="mb-3 text-muted-foreground">{props.description}</p>
<p className="mb-3 text-muted-foreground text-sm">{props.description}</p>

<ExportToCSVButton
className="top-6 right-6 mb-4 w-full bg-background md:absolute md:mb-0 md:flex md:w-auto"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function InAppWalletsSummary(props: {
);

return (
<div className="grid grid-cols-2 gap-4 lg:gap-6">
<div className="grid grid-cols-2 gap-4">
<Stat
label="Total Users"
value={allTimeStats?.uniqueWalletsConnected || 0}
Expand Down
Loading
Loading