Openstatus
www.openstatus.dev
1import { Link } from "@/components/common/link";
2import { Note, NoteButton } from "@/components/common/note";
3import { BillingAddons } from "@/components/content/billing-addons";
4import { DataTable } from "@/components/data-table/billing/data-table";
5import {
6 Dialog,
7 DialogContent,
8 DialogDescription,
9 DialogHeader,
10 DialogTitle,
11} from "@/components/ui/dialog";
12import { Separator } from "@/components/ui/separator";
13import { useTRPC } from "@/lib/trpc/client";
14import type { WorkspacePlan } from "@openstatus/db/src/schema";
15import { allPlans } from "@openstatus/db/src/schema/plan/config";
16import type { Addons, Limits } from "@openstatus/db/src/schema/plan/schema";
17import { getPlansForLimit } from "@openstatus/db/src/schema/plan/utils";
18import type { DialogProps } from "@radix-ui/react-dialog";
19import { useQuery } from "@tanstack/react-query";
20import { CalendarClock } from "lucide-react";
21
22const PLANS = {
23 free: ["starter", "team"],
24 starter: ["team"],
25 team: [],
26} satisfies Record<WorkspacePlan, WorkspacePlan[]>;
27
28export function UpgradeDialog(
29 props: DialogProps & {
30 limit?: keyof Limits;
31 restrictTo?: WorkspacePlan[];
32 },
33) {
34 const trpc = useTRPC();
35 const { data: workspace } = useQuery(trpc.workspace.get.queryOptions());
36
37 if (!workspace) return null;
38
39 const planAddons = allPlans[workspace.plan].addons;
40
41 const getRestrictTo = () => {
42 if (props.restrictTo) return props.restrictTo;
43 if (props.limit) return getPlansForLimit(workspace.plan, props.limit);
44 return PLANS[workspace.plan];
45 };
46
47 const restrictTo = getRestrictTo();
48
49 const addon =
50 props.limit && Object.prototype.hasOwnProperty.call(planAddons, props.limit)
51 ? (props.limit as keyof Addons)
52 : null;
53
54 return (
55 <Dialog {...props}>
56 <DialogContent className="max-h-[80vh] overflow-y-auto sm:max-w-2xl">
57 <DialogHeader>
58 <DialogTitle>Upgrade Workspace</DialogTitle>
59 <DialogDescription>
60 Upgrade your workspace to support more monitors, status pages,
61 regions, and much more. Get an overview within your{" "}
62 <Link
63 onClick={() => props.onOpenChange?.(false)}
64 href="/settings/billing"
65 >
66 billing settings
67 </Link>
68 .
69 </DialogDescription>
70 </DialogHeader>
71 {addon && planAddons[addon] ? (
72 <>
73 <BillingAddons
74 label={planAddons[addon].title}
75 description={planAddons[addon].description}
76 addon={addon}
77 workspace={workspace}
78 />
79 <Separator />
80 </>
81 ) : null}
82 {restrictTo.length === 0 ? (
83 <Note>
84 <CalendarClock />
85 Please contact us to upgrade your plan.
86 <NoteButton variant="outline" asChild>
87 <a
88 href="https://openstatus.dev/cal"
89 target="_blank"
90 rel="noreferrer"
91 className="text-nowrap"
92 >
93 Book a call
94 </a>
95 </NoteButton>
96 </Note>
97 ) : (
98 <DataTable restrictTo={restrictTo} />
99 )}
100 </DialogContent>
101 </Dialog>
102 );
103}