From 9f6c40fd4260b1f8e442cd68fad7ba7255f82bd5 Mon Sep 17 00:00:00 2001 From: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Date: Thu, 24 Aug 2023 15:15:02 +0530 Subject: [PATCH] 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 --- .../settings/billing/PricingTable.tsx | 18 ++++------- .../settings/billing/loading.tsx | 12 ++++++++ .../[environmentId]/settings/billing/page.tsx | 30 ++++++++++++++++--- apps/web/app/error.tsx | 11 +++---- apps/web/app/not-found.tsx | 18 +++++++++++ packages/lib/services/team.ts | 1 + packages/types/v1/teams.ts | 1 + 7 files changed, 68 insertions(+), 23 deletions(-) create mode 100644 apps/web/app/(app)/environments/[environmentId]/settings/billing/loading.tsx create mode 100644 apps/web/app/not-found.tsx diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/billing/PricingTable.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/billing/PricingTable.tsx index dcf089c2f3..6d70546f6c 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/billing/PricingTable.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/billing/PricingTable.tsx @@ -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 ; - - if (!session || isErrorTeam) return ; const openCustomerPortal = async () => { setLoadingCustomerPortal(true); diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/billing/loading.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/billing/loading.tsx new file mode 100644 index 0000000000..d40cc3daa2 --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/settings/billing/loading.tsx @@ -0,0 +1,12 @@ +export default function Loading() { + return ( +
+

Billing & Plan

+
+
+
+
+
+
+ ); +} diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/billing/page.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/billing/page.tsx index 3110604cdb..d2d21c1c9e 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/billing/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/billing/page.tsx @@ -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 ( -
- - -
+ <> +
+ + +
+ ); } diff --git a/apps/web/app/error.tsx b/apps/web/app/error.tsx index 2ee5c72a63..33ec496b96 100644 --- a/apps/web/app/error.tsx +++ b/apps/web/app/error.tsx @@ -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 (
diff --git a/apps/web/app/not-found.tsx b/apps/web/app/not-found.tsx new file mode 100644 index 0000000000..aa41f6e1c7 --- /dev/null +++ b/apps/web/app/not-found.tsx @@ -0,0 +1,18 @@ +import { Button } from "@formbricks/ui"; + +export default function NotFound() { + return ( + <> +
+

404

+

Page not found

+

+ Sorry, we couldn’t find the page you’re looking for. +

+ +
+ + ); +} diff --git a/packages/lib/services/team.ts b/packages/lib/services/team.ts index 6babcebaaf..9ca2775e29 100644 --- a/packages/lib/services/team.ts +++ b/packages/lib/services/team.ts @@ -29,6 +29,7 @@ export const select = { updatedAt: true, name: true, plan: true, + stripeCustomerId: true, }; export const getTeamByEnvironmentId = cache(async (environmentId: string): Promise => { diff --git a/packages/types/v1/teams.ts b/packages/types/v1/teams.ts index 2c5416a605..bebee164db 100644 --- a/packages/types/v1/teams.ts +++ b/packages/types/v1/teams.ts @@ -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;