Skip to content

Commit 854496b

Browse files
committed
[TOOL-3526] Dashboard: Add billing status alert banners
1 parent 088b6e2 commit 854496b

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"use client";
2+
3+
import { redirectToBillingPortal } from "@/actions/billing";
4+
import { BillingPortalButton } from "@/components/billing";
5+
import { Spinner } from "@chakra-ui/react";
6+
import { ArrowRightIcon } from "lucide-react";
7+
import { useState } from "react";
8+
9+
function PaymentAlertBanner(props: {
10+
title: string;
11+
description: React.ReactNode;
12+
teamSlug: string;
13+
}) {
14+
const [isRouteLoading, setIsRouteLoading] = useState(false);
15+
16+
return (
17+
<div className="flex flex-col border-b bg-card px-4 py-6 lg:items-center lg:text-center">
18+
<h3 className="font-semibold text-red-500 text-xl tracking-tight">
19+
{props.title}
20+
</h3>
21+
<p className="mt-1 mb-4 text-muted-foreground text-sm">
22+
{props.description}
23+
</p>
24+
<BillingPortalButton
25+
className="gap-2"
26+
size="sm"
27+
teamSlug={props.teamSlug}
28+
redirectPath={`/team/${props.teamSlug}`}
29+
redirectToBillingPortal={redirectToBillingPortal}
30+
onClick={() => {
31+
setIsRouteLoading(true);
32+
}}
33+
>
34+
Pay Invoices
35+
{isRouteLoading ? (
36+
<Spinner className="size-4" />
37+
) : (
38+
<ArrowRightIcon className="size-4" />
39+
)}
40+
</BillingPortalButton>
41+
</div>
42+
);
43+
}
44+
45+
export function PastDueBanner(props: {
46+
teamSlug: string;
47+
}) {
48+
return (
49+
<PaymentAlertBanner
50+
title="You have unpaid invoices"
51+
description={
52+
<>
53+
Your service will be cut off when you hit a max unpaid amount <br />{" "}
54+
Pay your invoices to ensure continued access to thirdweb services
55+
</>
56+
}
57+
teamSlug={props.teamSlug}
58+
/>
59+
);
60+
}
61+
62+
export function ServiceCutOffBanner(props: {
63+
teamSlug: string;
64+
}) {
65+
return (
66+
<PaymentAlertBanner
67+
title="Your service is cut off"
68+
description={
69+
<>
70+
Your service is cut off due to unpaid invoices <br /> Please pay your
71+
invoices to continue using thirdweb services
72+
</>
73+
}
74+
teamSlug={props.teamSlug}
75+
/>
76+
);
77+
}

apps/dashboard/src/app/team/[team_slug]/layout.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { AppFooter } from "@/components/blocks/app-footer";
33
import { redirect } from "next/navigation";
44
import { TWAutoConnect } from "../../components/autoconnect";
55
import { SaveLastVisitedTeamPage } from "../components/last-visited-page/SaveLastVisitedPage";
6+
import {
7+
PastDueBanner,
8+
ServiceCutOffBanner,
9+
} from "./(team)/_components/AlertBanners";
610

711
export default async function RootTeamLayout(props: {
812
children: React.ReactNode;
@@ -17,8 +21,19 @@ export default async function RootTeamLayout(props: {
1721

1822
return (
1923
<div className="flex min-h-dvh flex-col">
20-
<div className="flex grow flex-col">{props.children}</div>
24+
<div className="flex grow flex-col">
25+
{team.billingStatus === "pastDue" && (
26+
<PastDueBanner teamSlug={team_slug} />
27+
)}
28+
29+
{team.billingStatus === "invalidPayment" && (
30+
<ServiceCutOffBanner teamSlug={team_slug} />
31+
)}
32+
33+
{props.children}
34+
</div>
2135
<TWAutoConnect />
36+
2237
<AppFooter />
2338
<SaveLastVisitedTeamPage />
2439
</div>

0 commit comments

Comments
 (0)