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
@@ -1,15 +1,29 @@
"use client";

import { Button } from "@/components/ui/button";
import { useDashboardRouter } from "@/lib/DashboardRouter";
import { AlertTriangleIcon } from "lucide-react";

export function StripeRedirectErrorPage(props: {
errorMessage: string;
}) {
const router = useDashboardRouter();

return (
<div className="flex min-h-dvh items-center justify-center">
<div className="flex flex-col items-center text-center text-sm">
<div className="mb-4 rounded-full border p-2">
<AlertTriangleIcon className="size-5 text-destructive-text" />
</div>
<p className="font-medium text-base">{props.errorMessage}</p>

<Button
variant="outline"
className="mt-4"
onClick={() => router.back()}
>
Go back
</Button>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,16 @@ export default async function CheckoutPage(props: {
break;
}
default: {
const billingUrl = await getBillingCheckoutUrl({
const response = await getBillingCheckoutUrl({
teamSlug: params.team_slug,
sku: decodeURIComponent(params.sku) as Exclude<ProductSKU, null>,
});

if (!billingUrl) {
return (
<StripeRedirectErrorPage errorMessage="Failed to load checkout page" />
);
if (response.status === "error") {
return <StripeRedirectErrorPage errorMessage={response.error} />;
}

redirect(billingUrl);
redirect(response.data);
break;
}
}
Expand Down
42 changes: 36 additions & 6 deletions apps/dashboard/src/app/(app)/(stripe)/utils/billing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { getAuthToken } from "../../api/lib/getAuthToken";
export async function getBillingCheckoutUrl(options: {
teamSlug: string;
sku: Exclude<ProductSKU, null>;
}): Promise<string | undefined> {
}) {
const token = await getAuthToken();

if (!token) {
return undefined;
return {
status: "error",
error: "You are not logged in",
} as const;
}

const res = await fetch(
Expand All @@ -29,16 +32,43 @@ export async function getBillingCheckoutUrl(options: {
},
);
if (!res.ok) {
console.error("Failed to create checkout link", await res.json());
return undefined;
const text = await res.text();
console.error("Failed to create checkout link", text, res.status);
switch (res.status) {
case 402: {
return {
status: "error",
error:
"You have outstanding invoices, please pay these first before re-subscribing.",
} as const;
}
case 429: {
return {
status: "error",
error: "Too many requests, please try again later.",
} as const;
}
default: {
return {
status: "error",
error: "An unknown error occurred, please try again later.",
} as const;
}
}
}

const json = await res.json();
if (!json.result) {
return undefined;
return {
status: "error",
error: "An unknown error occurred, please try again later.",
} as const;
}

return json.result as string;
return {
status: "success",
data: json.result as string,
} as const;
}

export async function getPlanCancelUrl(options: {
Expand Down
Loading