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
173 changes: 97 additions & 76 deletions apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,28 @@ import { EmptyState } from "../../components/Analytics/EmptyState";
import { PieChartCard } from "../../components/Analytics/PieChartCard";

import { getTeamBySlug } from "@/api/team";
import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage";
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
import { getAccount } from "app/account/settings/getAccount";
import { EmptyStateCard } from "app/team/components/Analytics/EmptyStateCard";
import { Changelog, type ChangelogItem } from "components/dashboard/Changelog";
import { Suspense } from "react";
import { TotalSponsoredChartCardUI } from "./_components/TotalSponsoredCard";

// revalidate every 5 minutes
export const revalidate = 300;

type SearchParams = {
usersChart?: string;
from?: string;
to?: string;
type?: string;
interval?: string;
};

export default async function TeamOverviewPage(props: {
params: { team_slug: string };
searchParams: {
usersChart?: string;
from?: string;
to?: string;
type?: string;
interval?: string;
};
params: Promise<{ team_slug: string }>;
searchParams: Promise<SearchParams>;
}) {
const changelog = await getChangelog();
const [params, searchParams] = await Promise.all([
Expand All @@ -67,6 +72,43 @@ export default async function TeamOverviewPage(props: {
redirect("/login");
}

return (
<div className="flex grow flex-col">
<div className="border-b">
<AnalyticsHeader
title="Team Overview"
interval={interval}
range={range}
/>
</div>
<div className="flex grow flex-col justify-between gap-10 md:container md:pt-8 md:pb-16 xl:flex-row">
<Suspense fallback={<GenericLoadingPage />}>
<OverviewPageContent
account={account}
range={range}
interval={interval}
searchParams={searchParams}
/>
</Suspense>
<div className="shrink-0 max-md:container max-xl:hidden lg:w-[320px]">
<h2 className="mb-4 font-semibold text-lg tracking-tight">
Latest changes
</h2>
<Changelog changelog={changelog} />
</div>
</div>
</div>
);
}

async function OverviewPageContent(props: {
account: Account;
range: Range;
interval: "day" | "week";
searchParams: SearchParams;
}) {
const { account, range, interval, searchParams } = props;

const [
walletConnections,
walletUserStatsTimeSeries,
Expand Down Expand Up @@ -116,77 +158,56 @@ export default async function TeamOverviewPage(props: {
inAppWalletUsage.length === 0 &&
userOpUsage.length === 0;

if (isEmpty) {
return <EmptyState />;
}

return (
<div>
<div className="w-full border-border-800 border-b px-6 dark:bg-muted/50">
<AnalyticsHeader
title="Team Overview"
interval={interval}
range={range}
/>
</div>
<div className="flex flex-col justify-between gap-16 md:container md:pt-8 md:pb-16 xl:flex-row">
<div className="grow">
{isEmpty ? (
<div className="container p-6">
<EmptyState />
</div>
) : (
<div className="space-y-6">
{walletUserStatsTimeSeries.some((w) => w.totalUsers !== 0) ? (
<div className="">
<UsersChartCard
userStats={walletUserStatsTimeSeries}
searchParams={searchParams}
/>
</div>
) : (
<EmptyStateCard
metric="Connect"
link="https://portal.thirdweb.com/connect/quickstart"
/>
)}
<div className="grid gap-6 max-md:px-6 md:grid-cols-2">
{walletConnections.length > 0 ? (
<WalletDistributionCard data={walletConnections} />
) : (
<EmptyStateCard
metric="Connect"
link="https://portal.thirdweb.com/connect/quickstart"
/>
)}
{inAppWalletUsage.length > 0 ? (
<AuthMethodDistributionCard data={inAppWalletUsage} />
) : (
<EmptyStateCard
metric="In-App Wallets"
link="https://portal.thirdweb.com/typescript/v5/inAppWallet"
/>
)}
</div>
{userOpUsage.length > 0 ? (
<TotalSponsoredChartCardUI
searchParams={searchParams}
data={userOpUsageTimeSeries}
aggregatedData={userOpUsage}
className="max-md:rounded-none max-md:border-r-0 max-md:border-l-0"
/>
) : (
<EmptyStateCard
metric="Sponsored Transactions"
link="https://portal.thirdweb.com/typescript/v5/account-abstraction/get-started"
/>
)}
</div>
)}
</div>
<div className="shrink-0 max-md:container max-xl:hidden lg:w-[320px]">
<h2 className="mb-4 font-semibold text-lg tracking-tight">
Latest changes
</h2>
<Changelog changelog={changelog} />
<div className="flex grow flex-col gap-6">
{walletUserStatsTimeSeries.some((w) => w.totalUsers !== 0) ? (
<div className="">
<UsersChartCard
userStats={walletUserStatsTimeSeries}
searchParams={searchParams}
/>
</div>
) : (
<EmptyStateCard
metric="Connect"
link="https://portal.thirdweb.com/connect/quickstart"
/>
)}
<div className="grid gap-6 max-md:px-6 md:grid-cols-2">
{walletConnections.length > 0 ? (
<WalletDistributionCard data={walletConnections} />
) : (
<EmptyStateCard
metric="Connect"
link="https://portal.thirdweb.com/connect/quickstart"
/>
)}
{inAppWalletUsage.length > 0 ? (
<AuthMethodDistributionCard data={inAppWalletUsage} />
) : (
<EmptyStateCard
metric="In-App Wallets"
link="https://portal.thirdweb.com/typescript/v5/inAppWallet"
/>
)}
</div>
{userOpUsage.length > 0 ? (
<TotalSponsoredChartCardUI
searchParams={searchParams}
data={userOpUsageTimeSeries}
aggregatedData={userOpUsage}
className="max-md:rounded-none max-md:border-r-0 max-md:border-l-0"
/>
) : (
<EmptyStateCard
metric="Sponsored Transactions"
link="https://portal.thirdweb.com/typescript/v5/account-abstraction/get-started"
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ export function AnalyticsHeader(props: {
const { title, interval, range } = props;

return (
<div className="container flex flex-col items-start gap-6 px-2 py-6 md:h-[120px] md:flex-row md:items-center md:p-6 md:py-0">
<div className="container flex flex-col items-start gap-3 py-10 md:flex-row md:items-center">
<div className="flex-1">
<h1 className="font-semibold text-3xl text-foreground">{title}</h1>
<h1 className="font-semibold text-2xl tracking-tight md:text-3xl">
{title}
</h1>
</div>
<RangeSelector interval={interval} range={range} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import walletsIcon from "../../../../../public/assets/tw-icons/wallets.svg";

export function EmptyState() {
return (
<section className="flex items-start justify-center md:min-h-[500px]">
<section className="flex w-full items-start justify-center md:min-h-[500px]">
<div className="group container flex flex-col items-center justify-center gap-8 rounded-lg border bg-card p-6 py-24">
<div className="flex max-w-[500px] flex-col items-center justify-center gap-6">
<AnimatedIcons />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function RangeSelector({
});

return (
<div className="flex flex-col justify-end gap-3 sm:flex-row">
<div className="flex justify-end gap-4">
<DateRangeSelector
range={localRange}
setRange={(newRange) => {
Expand Down
Loading