"use client"; import { Check } from "lucide-react"; import { Fragment, useTransition } from "react"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { config as featureGroups, plans } from "@/data/plans"; import { useCookieState } from "@/hooks/use-cookie-state"; import { getStripe } from "@/lib/stripe"; import { useTRPC } from "@/lib/trpc/client"; import { cn } from "@/lib/utils"; import type { WorkspacePlan } from "@openstatus/db/src/schema"; import { getAddonPriceConfig, getPriceConfig, } from "@openstatus/db/src/schema/plan/utils"; import { useMutation, useQuery } from "@tanstack/react-query"; const BASE_URL = process.env.NODE_ENV === "production" ? "https://app.openstatus.dev" : "http://localhost:3000"; export function DataTable({ restrictTo }: { restrictTo?: WorkspacePlan[] }) { const [currency] = useCookieState("x-currency", "USD"); const trpc = useTRPC(); const [isPending, startTransition] = useTransition(); const { data: workspace } = useQuery(trpc.workspace.get.queryOptions()); const checkoutSessionMutation = useMutation( trpc.stripeRouter.getCheckoutSession.mutationOptions({ onSuccess: async (data) => { if (!data) return; const stripe = await getStripe(); stripe?.redirectToCheckout({ sessionId: data.id }); }, }), ); if (!workspace) return null; const filteredPlans = Object.values(plans).filter((plan) => restrictTo ? restrictTo.includes(plan.id) : true, ); return ( A list to compare the different features by plan. Features comparison {filteredPlans.map(({ id, ...plan }) => { const isCurrentPlan = workspace.plan === id; const price = getPriceConfig(id, currency); return (

{plan.title}

{plan.description}

{new Intl.NumberFormat(price.locale, { style: "currency", currency: price.currency, }).format(price.value)} /month

); })}
{Object.entries(featureGroups).map( ([groupKey, { label, features }]) => ( {label} {features.map( ({ value, label: featureLabel, monthly, badge }) => (
{featureLabel}{" "} {badge ? ( {badge} ) : null}
{filteredPlans.map((plan) => { const limitValue = plan.limits[value as keyof typeof plan.limits]; const isAddon = value in plan.addons; function renderContent() { if (isAddon) { const price = getAddonPriceConfig( plan.id, value as keyof typeof plan.addons, currency, ); if (!price) return null; const isNumber = typeof limitValue === "number"; return (
{isNumber ? new Intl.NumberFormat("us") .format(limitValue) .toString() : null} {isNumber ? " + " : ""} {new Intl.NumberFormat(price.locale, { style: "currency", currency: price.currency, }).format(price.value)} {isNumber ? "/mo./each" : "/mo."}
); } if (typeof limitValue === "boolean") { return limitValue ? ( ) : ( ); } if (typeof limitValue === "number") { return new Intl.NumberFormat("us") .format(limitValue) .toString(); } // TODO: create a format function for this in @data/plans if (value === "regions" && Array.isArray(limitValue)) { return limitValue?.length ?? 0; } if ( Array.isArray(limitValue) && limitValue.length > 0 ) { return limitValue[0]; } return limitValue; } return ( {renderContent()} {monthly ? "/mo." : ""} ); })}
), )}
), )}
); }