mirror of
https://github.com/documenso/documenso.git
synced 2026-07-24 00:43:40 +10:00
feat: add guards and subscription ui
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { classNames } from "@documenso/lib";
|
||||
import { STRIPE_PLANS, fetchCheckoutSession, useSubscription } from "@documenso/lib/stripe";
|
||||
import { Button } from "@documenso/ui";
|
||||
import { Switch } from "@headlessui/react";
|
||||
|
||||
export const BillingPlans = () => {
|
||||
const { subscription, hasSubscription, isLoading } = useSubscription();
|
||||
const [isAnnual, setIsAnnual] = useState(true);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!subscription &&
|
||||
STRIPE_PLANS.map((plan) => (
|
||||
<div key={plan.name} className="rounded-lg border py-4 px-6">
|
||||
<h3 className="text-center text-lg font-medium leading-6 text-gray-900">{plan.name}</h3>
|
||||
|
||||
<div className="my-4 flex justify-center">
|
||||
<Switch.Group as="div" className="flex items-center">
|
||||
<Switch
|
||||
checked={isAnnual}
|
||||
onChange={setIsAnnual}
|
||||
className={classNames(
|
||||
isAnnual ? "bg-neon-600" : "bg-gray-200",
|
||||
"relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-neon-600 focus:ring-offset-2"
|
||||
)}>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
isAnnual ? "translate-x-5" : "translate-x-0",
|
||||
"pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
<Switch.Label as="span" className="ml-3 text-sm">
|
||||
<span className="font-medium text-gray-900">Annual billing</span>{" "}
|
||||
<span className="text-gray-500">(Save $60)</span>
|
||||
</Switch.Label>
|
||||
</Switch.Group>
|
||||
</div>
|
||||
|
||||
<p className="mt-2 text-center text-gray-500">
|
||||
${(isAnnual ? plan.prices.yearly.price : plan.prices.monthly.price).toFixed(2)}{" "}
|
||||
<span className="text-sm text-gray-400">{isAnnual ? "/yr" : "/mo"}</span>
|
||||
</p>
|
||||
|
||||
<p className="mt-4 text-center text-sm text-gray-500">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Corrupti voluptates delectus
|
||||
doloremque hic vel!
|
||||
</p>
|
||||
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
className="w-full"
|
||||
disabled={isLoading}
|
||||
onClick={() =>
|
||||
fetchCheckoutSession({
|
||||
priceId: isAnnual ? plan.prices.yearly.priceId : plan.prices.monthly.priceId,
|
||||
}).then((res) => {
|
||||
if (res.success) {
|
||||
window.location.href = res.url;
|
||||
}
|
||||
})
|
||||
}>
|
||||
Subscribe
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -4,9 +4,18 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { updateUser } from "@documenso/features";
|
||||
import { getUser } from "@documenso/lib/api";
|
||||
import {
|
||||
STRIPE_PLANS,
|
||||
fetchCheckoutSession,
|
||||
fetchPortalSession,
|
||||
isSubscriptionsEnabled,
|
||||
useSubscription,
|
||||
} from "@documenso/lib/stripe";
|
||||
import { SubscriptionStatus } from '@prisma/client'
|
||||
import { Button } from "@documenso/ui";
|
||||
import { CreditCardIcon, KeyIcon, UserCircleIcon } from "@heroicons/react/24/outline";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { BillingPlans } from "./billing-plans";
|
||||
|
||||
const subNavigation = [
|
||||
{
|
||||
@@ -35,6 +44,7 @@ function classNames(...classes: any) {
|
||||
|
||||
export default function Setttings() {
|
||||
const session = useSession();
|
||||
const { subscription, hasSubscription } = useSubscription();
|
||||
const [user, setUser] = useState({
|
||||
email: "",
|
||||
name: "",
|
||||
@@ -179,24 +189,63 @@ export default function Setttings() {
|
||||
</div>
|
||||
|
||||
<div
|
||||
hidden={subNavigation.filter((e) => e.current)[0]?.name !== subNavigation?.[2]?.name}
|
||||
hidden={
|
||||
subNavigation.find((e) => e.current)?.name !== subNavigation?.[2]?.name
|
||||
}
|
||||
className="min-h-[251px] divide-y divide-gray-200 lg:col-span-9">
|
||||
{/* Billing section */}
|
||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||
<div>
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900">Billing</h2>
|
||||
|
||||
{!isSubscriptionsEnabled() && (
|
||||
<p className="mt-2 text-sm text-gray-500">
|
||||
Subscriptions are not enabled on this instance, you have nothing to do here.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{isSubscriptionsEnabled() && <>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Your subscription is currently <strong>{user?.subscription ? 'Active' : 'Inactive'}</strong>.
|
||||
Your subscription is currently{" "}
|
||||
<strong>{subscription?.status && subscription?.status !== SubscriptionStatus.INACTIVE ? "Active" : "Inactive"}</strong>.
|
||||
</p>
|
||||
|
||||
{subscription?.status === SubscriptionStatus.PAST_DUE && (
|
||||
<p className="mt-1 text-sm text-red-500">
|
||||
Your subscription is past due. Please update your payment details to continue
|
||||
using the service without interruption.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
We use Stripe to process payments. Your card details are never stored on our
|
||||
servers.
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Est consectetur magnam
|
||||
illo aperiam expedita porro eos eum nam sapiente.
|
||||
</p>
|
||||
|
||||
<div className="mt-8">
|
||||
<Button onClick={() => {}}>Manage my subscription</Button>
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2">
|
||||
|
||||
<BillingPlans />
|
||||
</div>
|
||||
|
||||
{subscription && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (isSubscriptionsEnabled() && subscription?.customerId) {
|
||||
fetchPortalSession({
|
||||
id: subscription.customerId,
|
||||
}).then((res) => {
|
||||
if (res.success) {
|
||||
window.location.href = res.url;
|
||||
}
|
||||
});
|
||||
}
|
||||
}}>
|
||||
Manage my subscription
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user