Skip to content

Commit 3f53b7c

Browse files
authored
Merge pull request #352 from mfts/feat/billing-update
feat: add and update pricing / billing pages
2 parents 134d967 + 07af6f9 commit 3f53b7c

File tree

4 files changed

+319
-177
lines changed

4 files changed

+319
-177
lines changed

components/billing/upgrade-plan-modal.tsx

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
33
import { Button } from "@/components/ui/button";
44
import { motion } from "framer-motion";
55
import { STAGGER_CHILD_VARIANTS } from "@/lib/constants";
6-
import CheckCircle2 from "@/components/shared/icons/check-cirlce-2";
76
import { capitalize } from "@/lib/utils";
87
import { PLANS } from "@/lib/stripe/utils";
98
import { getStripe } from "@/lib/stripe/client";
109
import { Badge } from "../ui/badge";
1110
import { useTeam } from "@/context/team-context";
1211
import { useAnalytics } from "@/lib/analytics";
1312
import React from "react";
13+
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
14+
import { CheckIcon } from "lucide-react";
1415

1516
export function UpgradePlanModal({
1617
clickedPlan,
@@ -19,28 +20,55 @@ export function UpgradePlanModal({
1920
setOpen,
2021
children,
2122
}: {
22-
clickedPlan: "Enterprise" | "Pro";
23+
clickedPlan: "Business" | "Pro";
2324
trigger?: string;
2425
open?: boolean;
2526
setOpen?: React.Dispatch<React.SetStateAction<boolean>>;
2627
children?: React.ReactNode;
2728
}) {
28-
const [plan, setPlan] = useState<"Pro" | "Enterprise">(clickedPlan);
29+
const [plan, setPlan] = useState<"Pro" | "Business">(clickedPlan);
2930
const [period, setPeriod] = useState<"monthly" | "yearly">("monthly");
3031
const [clicked, setClicked] = useState<boolean>(false);
3132
const teamInfo = useTeam();
3233
const analytics = useAnalytics();
3334

3435
const features = useMemo(() => {
36+
if (plan === "Pro") {
37+
return [
38+
"Folders",
39+
"3 team members",
40+
"Unlimited link views",
41+
"Custom domains",
42+
"Custom branding",
43+
"Notion documents",
44+
"AI Document Assistant incl. 1500 credits",
45+
];
46+
}
47+
48+
if (plan === "Business") {
49+
return [
50+
"Unlimited subfolder levels",
51+
"10 team members",
52+
"Unlimited documents",
53+
"Unlimited link views",
54+
"Custom domains",
55+
"Custom branding",
56+
"Notion documents",
57+
"Data room (coming soon)",
58+
"Shareable folders (coming soon)",
59+
"AI Document Assistant incl. 2500 credits",
60+
"Priority Support",
61+
];
62+
}
63+
3564
return [
65+
"Folders",
66+
"3 team members",
67+
"Unlimited link views",
3668
"Custom domains",
3769
"Custom branding",
3870
"Notion documents",
39-
"Unlimited link views",
40-
"Unlimited documents",
41-
"Team members",
4271
"AI Document Assistant incl. 1500 credits",
43-
...(plan === "Enterprise" ? ["Priority Support"] : []),
4472
];
4573
}, [plan]);
4674

@@ -103,7 +131,18 @@ export function UpgradePlanModal({
103131
Enjoy higher limits and extra features with our {plan} plan.
104132
</motion.p>
105133
</motion.div>
106-
<div className="bg-background px-4 py-8 text-left sm:px-16">
134+
135+
<div className="bg-background px-4 pb-8 text-left sm:px-16">
136+
<Tabs className="pb-4" defaultValue={plan}>
137+
<TabsList className="grid w-full grid-cols-2">
138+
<TabsTrigger value="Pro" onClick={() => setPlan("Pro")}>
139+
Pro
140+
</TabsTrigger>
141+
<TabsTrigger value="Business" onClick={() => setPlan("Business")}>
142+
Business
143+
</TabsTrigger>
144+
</TabsList>
145+
</Tabs>
107146
<motion.div
108147
className="flex flex-col space-y-3"
109148
variants={STAGGER_CHILD_VARIANTS}
@@ -121,17 +160,15 @@ export function UpgradePlanModal({
121160
className="text-sm font-normal normal-case"
122161
>{`€${
123162
PLANS.find((p) => p.name === plan)!.price[period].amount
124-
}/month`}</Badge>
163+
}/${period.replace("ly", "")}`}</Badge>
125164
</div>
126165
<button
127166
onClick={() => {
128167
setPeriod(period === "monthly" ? "yearly" : "monthly");
129168
}}
130169
className="text-xs text-muted-foreground underline underline-offset-4 transition-colors hover:text-gray-800 hover:dark:text-muted-foreground/80"
131170
>
132-
{period === "monthly"
133-
? "Get 2 months free 🎁"
134-
: "Switch to monthly"}
171+
{period === "monthly" ? "Want 20% off?" : "Switch to monthly"}
135172
</button>
136173
</div>
137174
<motion.div
@@ -150,9 +187,12 @@ export function UpgradePlanModal({
150187
<motion.div
151188
key={i}
152189
variants={STAGGER_CHILD_VARIANTS}
153-
className="flex items-center space-x-2 text-sm text-muted-foreground"
190+
className="flex items-center gap-x-3 text-sm text-muted-foreground"
154191
>
155-
<CheckCircle2 className="h-5 w-5 text-emerald-500" />
192+
<CheckIcon
193+
className="h-5 w-5 flex-none text-[#fb7a00]"
194+
aria-hidden="true"
195+
/>
156196
<span>{feature}</span>
157197
</motion.div>
158198
))}
@@ -194,16 +234,7 @@ export function UpgradePlanModal({
194234
target="_blank"
195235
className="text-center text-xs text-muted-foreground underline-offset-4 transition-all hover:text-gray-800 hover:dark:text-muted-foreground/80 hover:underline"
196236
>
197-
Papermark Enterprise
198-
</a>
199-
<p className="text-muted-foreground"></p>
200-
<a
201-
href={`${process.env.NEXT_PUBLIC_BASE_URL}/pricing`}
202-
target="_blank"
203-
rel="noopener noreferrer"
204-
className="text-center text-xs text-muted-foreground underline-offset-4 transition-all hover:text-gray-800 hover:dark:text-muted-foreground/80 hover:underline"
205-
>
206-
Compare plans
237+
Looking for Papermark Enterprise?
207238
</a>
208239
</div>
209240
</motion.div>

lib/stripe/utils.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const PLANS = [
5151
},
5252
},
5353
yearly: {
54-
amount: 24,
54+
amount: 290,
5555
priceIds: {
5656
test: "price_1NmHHaFJyGSZ96lhXxg2fTr7",
5757
production: "price_1Op0fFFJyGSZ96lhPVrvzz5a", // new price
@@ -60,4 +60,24 @@ export const PLANS = [
6060
},
6161
},
6262
},
63+
{
64+
name: "Business",
65+
slug: "business",
66+
price: {
67+
monthly: {
68+
amount: 79,
69+
priceIds: {
70+
test: "price_1OuYgCFJyGSZ96lhF2gFs7Rs",
71+
production: "price_1OuYeIFJyGSZ96lhwH58Y1kU",
72+
},
73+
},
74+
yearly: {
75+
amount: 790,
76+
priceIds: {
77+
test: "price_1OuYgPFJyGSZ96lhKk6JzTf1",
78+
production: "price_1OuYedFJyGSZ96lhTaJx58pG",
79+
},
80+
},
81+
},
82+
},
6383
];

pages/pricing.tsx

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const tiers: {
2424
annually: string;
2525
};
2626
description: string;
27+
featureIntro: string;
2728
features: string[];
2829
bgColor: string;
2930
borderColor: string;
@@ -35,12 +36,14 @@ const tiers: {
3536
name: "Free",
3637
id: "tier-free",
3738
href: "/login",
38-
price: { monthly: "€0", annually: "$0" },
39+
price: { monthly: "€0", annually: "0" },
3940
description: "The essentials to start sharing documents securely.",
41+
featureIntro: "What's included:",
4042
features: [
4143
"1 user",
4244
"Unlimited links",
43-
"Analytics for each page",
45+
"Page-by-page analytics",
46+
"30-day analytics retention",
4447
"Document sharing controls",
4548
],
4649

@@ -52,15 +55,16 @@ const tiers: {
5255
},
5356
{
5457
name: "Pro",
55-
id: "tier-freelancer",
58+
id: "tier-pro",
5659
href: "/login",
57-
price: { monthly: "€29", annually: "$290" },
58-
description:
59-
"The essentials to provide a branded experience for your documents.",
60+
price: { monthly: "€29", annually: "290" },
61+
description: "The branded experience for your documents.",
62+
featureIntro: "Everything in Free, plus:",
6063
features: [
61-
"Everything in Free, plus:",
62-
"Up to 3 active users",
64+
"3 users",
6365
"Custom domain",
66+
"Custom branding",
67+
"1-year analytics retention",
6468
"Advanced access controls",
6569
"Papermark AI",
6670
],
@@ -72,16 +76,18 @@ const tiers: {
7276
},
7377
{
7478
name: "Business",
75-
id: "tier-startup",
79+
id: "tier-business",
7680
href: "/login",
77-
price: { monthly: "€79", annually: "$790" },
81+
price: { monthly: "€79", annually: "790" },
7882
description: "A plan that scales with your rapidly growing business.",
83+
featureIntro: "Everything in Pro, plus:",
7984
features: [
80-
"Everything in Pro, plus:",
81-
"Up to 10 active users",
82-
"Data room",
85+
"10 users",
86+
"Unlimited documents",
87+
"Unlimited subfolder levels",
8388
"Large file uploads",
84-
"Custom Branding",
89+
"Data rooms (coming soon)",
90+
"Shareable folders (coming soon)",
8591
"24h Priority Support",
8692
],
8793
bgColor: "#fb7a00",
@@ -94,12 +100,14 @@ const tiers: {
94100
name: "Enterprise",
95101
id: "tier-enterprise",
96102
href: "https://cal.com/marcseitz/papermark",
97-
price: { monthly: "Custom", annually: "$" },
103+
price: { monthly: "Custom", annually: "Custom" },
98104
description: "Self-hosted and advanced infrastructure for your company.",
105+
featureIntro: "Tailored solutions:",
99106
features: [
100-
"Self-Hosted version",
107+
"Self-hosted version",
101108
"Unlimited users",
102109
"Unlimited documents",
110+
"Unlimited folders and subfolders",
103111
"Different file types",
104112
"Up to 5TB file uploads",
105113
"Dedicated support",
@@ -193,6 +201,7 @@ export default function PricingPage() {
193201
role="list"
194202
className="mt-8 space-y-3 text-sm leading-6 text-gray-600"
195203
>
204+
<li>{tier.featureIntro}</li>
196205
{tier.features.map((feature) => (
197206
<li key={feature} className="flex gap-x-3">
198207
<CheckIcon
@@ -214,17 +223,18 @@ export default function PricingPage() {
214223
});
215224
}}
216225
>
217-
<Button
218-
className="rounded-3xl hover:bg-gray-100"
219-
style={{
220-
backgroundColor: tier.bgColor,
221-
borderColor: tier.borderColor,
222-
color: tier.textColor,
223-
borderWidth: "1px",
224-
}}
225-
>
226-
{tier.buttonText}
227-
</Button>
226+
{tier.id === "tier-business" ? (
227+
<Button
228+
className="rounded-3xl text-base"
229+
variant="orange"
230+
>
231+
{tier.buttonText}
232+
</Button>
233+
) : (
234+
<Button className="rounded-3xl text-base text-gray-200 bg-black hover:bg-gray-900">
235+
{tier.buttonText}
236+
</Button>
237+
)}
228238
</Link>
229239
</div>
230240
</div>
@@ -234,7 +244,7 @@ export default function PricingPage() {
234244
</div>
235245

236246
<div className="w-full max-w-7xl px-4 md:px-8 mx-auto ">
237-
<div className="py-12 bg-[#fb7a00] rounded-3xl mx-auto px-6">
247+
<div className="py-12 bg-[#fb7a00] rounded-xl mx-auto px-6">
238248
<div className="flex lg:flex-row flex-col item-center justify-between space-y-10 lg:space-y-0">
239249
<h2 className="text-3xl text-nowrap">Looking to self-host?</h2>
240250
<div className="space-x-2 flex items-center">

0 commit comments

Comments
 (0)