Rewrite Billing page to React Server Components and new type system (#701)

* Moved billing page to RSC

* removed unused props

* ran pnpm format

* fix build error

* add 404 page, throw 404 on billing page when !IS_FORMBRICKS_CLOUD

---------

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Dhruwang Jariwala
2023-08-24 15:15:02 +05:30
committed by GitHub
parent 317a5463e9
commit 9f6c40fd42
7 changed files with 68 additions and 23 deletions
@@ -1,11 +1,11 @@
"use client";
import LoadingSpinner from "@/components/shared/LoadingSpinner";
import { useTeam } from "@/lib/teams/teams";
import { Badge, Button, ErrorComponent } from "@formbricks/ui";
import { TTeam } from "@formbricks/types/v1/teams";
import { Badge, Button } from "@formbricks/ui";
import { CheckIcon } from "@heroicons/react/24/outline";
import type { Session } from "next-auth";
import { useRouter } from "next/navigation";
import { useState } from "react";
import LoadingSpinner from "@/components/shared/LoadingSpinner";
// upated on 20th of July 2023
const stripeURl =
@@ -14,18 +14,12 @@ const stripeURl =
: "https://buy.stripe.com/test_8wMaHA3UWcACfuM3cc";
interface PricingTableProps {
environmentId: string;
session: Session | null;
team: TTeam;
}
export default function PricingTable({ environmentId, session }: PricingTableProps) {
export default function PricingTable({ team }: PricingTableProps) {
const router = useRouter();
const [loadingCustomerPortal, setLoadingCustomerPortal] = useState(false);
const { team, isLoadingTeam, isErrorTeam } = useTeam(environmentId);
if (isLoadingTeam) return <LoadingSpinner />;
if (!session || isErrorTeam) return <ErrorComponent />;
const openCustomerPortal = async () => {
setLoadingCustomerPortal(true);
@@ -0,0 +1,12 @@
export default function Loading() {
return (
<div>
<h2 className="my-4 text-2xl font-medium leading-6 text-slate-800">Billing & Plan</h2>
<div className="grid grid-cols-2 gap-4 rounded-lg p-8">
<div className=" h-[75vh] animate-pulse rounded-md bg-gray-200 "></div>
<div className=" h-96 animate-pulse rounded-md bg-gray-200"></div>
<div className="col-span-2 h-96 bg-gray-200 p-8"></div>
</div>
</div>
);
}
@@ -1,14 +1,36 @@
export const revalidate = REVALIDATION_INTERVAL;
import { IS_FORMBRICKS_CLOUD, REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import { getTeamByEnvironmentId } from "@formbricks/lib/services/team";
import { getServerSession } from "next-auth";
import { notFound } from "next/navigation";
import SettingsTitle from "../SettingsTitle";
import PricingTable from "./PricingTable";
export default async function ProfileSettingsPage({ params }) {
if (!IS_FORMBRICKS_CLOUD) {
notFound();
}
const session = await getServerSession(authOptions);
const team = await getTeamByEnvironmentId(params.environmentId);
if (!session) {
throw new Error("Unauthorized");
}
if (!team) {
throw new Error("Team not found");
}
return (
<div>
<SettingsTitle title="Billing & Plan" />
<PricingTable environmentId={params.environmentId} session={session} />
</div>
<>
<div>
<SettingsTitle title="Billing & Plan" />
<PricingTable team={team} />
</div>
</>
);
}
+4 -7
View File
@@ -1,14 +1,11 @@
"use client"; // Error components must be Client components
import { Button } from "@formbricks/ui";
import { ErrorComponent } from "@formbricks/ui";
import { useEffect } from "react";
import { Button, ErrorComponent } from "@formbricks/ui";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);
if (process.env.NODE_ENV === "development") {
console.log(error);
}
return (
<div className="flex h-full w-full flex-col items-center justify-center">
+18
View File
@@ -0,0 +1,18 @@
import { Button } from "@formbricks/ui";
export default function NotFound() {
return (
<>
<div className="mx-auto flex h-full max-w-xl flex-col items-center justify-center py-16 text-center">
<p className="text-sm font-semibold text-zinc-900 dark:text-white">404</p>
<h1 className="mt-2 text-2xl font-bold text-zinc-900 dark:text-white">Page not found</h1>
<p className="mt-2 text-base text-zinc-600 dark:text-zinc-400">
Sorry, we couldnt find the page youre looking for.
</p>
<Button href="/" className="mt-8">
Back to home
</Button>
</div>
</>
);
}
+1
View File
@@ -29,6 +29,7 @@ export const select = {
updatedAt: true,
name: true,
plan: true,
stripeCustomerId: true,
};
export const getTeamByEnvironmentId = cache(async (environmentId: string): Promise<TTeam | null> => {
+1
View File
@@ -6,6 +6,7 @@ export const ZTeam = z.object({
updatedAt: z.date(),
name: z.string(),
plan: z.enum(["free", "pro"]),
stripeCustomerId: z.string().nullable(),
});
export type TTeam = z.infer<typeof ZTeam>;