Update UI for billing page

feat/ai-courses
Kamran Ahmed 2 months ago
parent b31a447855
commit 715cb82fc9
  1. 117
      src/components/Billing/BillingPage.tsx
  2. 37
      src/components/Billing/EmptyBillingScreen.tsx

@ -12,6 +12,7 @@ import { UpgradeAccountModal } from './UpgradeAccountModal';
import { getUrlParams } from '../../lib/browser'; import { getUrlParams } from '../../lib/browser';
import { VerifyUpgrade } from './VerifyUpgrade'; import { VerifyUpgrade } from './VerifyUpgrade';
import { EmptyBillingScreen } from './EmptyBillingScreen'; import { EmptyBillingScreen } from './EmptyBillingScreen';
import { Calendar, RefreshCw, Loader2, AlertTriangle } from 'lucide-react';
export type CreateCustomerPortalBody = {}; export type CreateCustomerPortalBody = {};
@ -30,8 +31,11 @@ export function BillingPage() {
queryClient, queryClient,
); );
const { mutate: createCustomerPortal, isPending: isCreatingCustomerPortal } = const {
useMutation( mutate: createCustomerPortal,
isSuccess: isCreatingCustomerPortalSuccess,
isPending: isCreatingCustomerPortal,
} = useMutation(
{ {
mutationFn: (body: CreateCustomerPortalBody) => { mutationFn: (body: CreateCustomerPortalBody) => {
return httpPost<CreateCustomerPortalResponse>( return httpPost<CreateCustomerPortalResponse>(
@ -97,75 +101,108 @@ export function BillingPage() {
{showVerifyUpgradeModal && <VerifyUpgrade />} {showVerifyUpgradeModal && <VerifyUpgrade />}
{billingDetails?.status === 'none' && !isLoadingBillingDetails && ( {billingDetails?.status === 'none' && !isLoadingBillingDetails && (
<EmptyBillingScreen <EmptyBillingScreen onUpgrade={() => setShowUpgradeModal(true)} />
onUpgrade={() => setShowUpgradeModal(true)}
/>
)} )}
{billingDetails?.status !== 'none' && {billingDetails?.status !== 'none' &&
!isLoadingBillingDetails && !isLoadingBillingDetails &&
priceDetails && ( priceDetails && (
<> <div className="mt-1 max-w-3xl">
{billingDetails?.status === 'past_due' && ( {billingDetails?.status === 'past_due' && (
<div className="mb-4 rounded-md border border-red-300 bg-red-50 p-2 text-sm text-red-500"> <div className="mb-6 flex items-center gap-2 rounded-lg border border-red-300 bg-red-50 p-4 text-sm text-red-600">
We were not able to charge your card. Please update your payment <AlertTriangle className="h-5 w-5" />
information. <span>
We were not able to charge your card.{' '}
<button
disabled={
isCreatingCustomerPortal ||
isCreatingCustomerPortalSuccess
}
onClick={() => {
createCustomerPortal({});
}}
className="font-semibold underline underline-offset-4 disabled:cursor-not-allowed disabled:opacity-50"
>
Update payment information.
</button>
</span>
</div> </div>
)} )}
<div className="flex items-start gap-10"> <h2 className="mb-2 text-xl font-semibold text-black">
<div className="flex flex-col"> Current Subscription
<span className="text-gray-500">Plan</span> </h2>
<span className="mt-1 text-lg font-medium capitalize text-black">
{selectedPlanDetails?.name} <p className="mb-6 text-sm text-gray-500">
</span> Thank you for being a pro member. Your plan details are below.
</p>
<div className="flex flex-col gap-6 sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-4">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
<RefreshCw className="size-5 text-gray-600" />
</div> </div>
<div className="flex grow items-center justify-between gap-2"> <div>
<div className="flex flex-col"> <span className="text-xs uppercase tracking-wider text-gray-400">
<span className="text-gray-500">Payment</span> Payment
<span className="mt-1 text-lg font-medium capitalize text-black"> </span>
<h3 className="flex items-baseline text-lg font-semibold text-black">
${priceDetails.amount} ${priceDetails.amount}
<span className="text-sm font-normal text-gray-500"> <span className="ml-1 text-sm font-normal text-gray-500">
&nbsp;/ {priceDetails.interval} / {priceDetails.interval}
</span> </span>
</h3>
</div>
</div>
</div>
<div className="mt-6 border-t border-gray-100 pt-6">
<div className="flex items-start gap-4">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
<Calendar className="size-5 text-gray-600" />
</div>
<div>
<span className="text-xs uppercase tracking-wider text-gray-400">
{billingDetails?.cancelAtPeriodEnd
? 'Expires On'
: 'Renews On'}
</span> </span>
<h3 className="text-lg font-semibold text-black">
{formattedNextBillDate}
</h3>
</div>
</div> </div>
<div className="mt-8 flex flex-wrap gap-3">
{!shouldHideDeleteButton && ( {!shouldHideDeleteButton && (
<button <button
className="inline-flex items-center gap-1 self-end text-xs underline underline-offset-1 hover:text-gray-600" className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
onClick={() => { onClick={() => {
setShowUpgradeModal(true); setShowUpgradeModal(true);
}} }}
> >
Update Plan Switch Plan
</button> </button>
)} )}
</div>
</div>
<div className="mt-4 flex justify-between gap-2">
<div className="flex flex-col">
<span className="text-gray-500">
{billingDetails?.cancelAtPeriodEnd
? 'Expires On'
: 'Renews On'}
</span>
<span className="mt-1 text-lg font-medium capitalize text-black">
{formattedNextBillDate}
</span>
</div>
<button <button
className="inline-flex self-end text-xs underline underline-offset-1 hover:text-gray-600 disabled:cursor-not-allowed disabled:opacity-50" className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-colors hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
onClick={() => { onClick={() => {
createCustomerPortal({}); createCustomerPortal({});
}} }}
disabled={isCreatingCustomerPortal} disabled={
isCreatingCustomerPortal || isCreatingCustomerPortalSuccess
}
> >
Manage my Subscription {(isCreatingCustomerPortal ||
isCreatingCustomerPortalSuccess) && (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
)}
Manage Subscription
</button> </button>
</div> </div>
</> </div>
</div>
)} )}
</> </>
); );

@ -5,6 +5,7 @@ import {
MessageCircleIcon, MessageCircleIcon,
SparklesIcon, SparklesIcon,
Zap, Zap,
CheckCircle,
} from 'lucide-react'; } from 'lucide-react';
type EmptyBillingScreenProps = { type EmptyBillingScreenProps = {
@ -38,31 +39,45 @@ export function EmptyBillingScreen(props: EmptyBillingScreenProps) {
const { onUpgrade } = props; const { onUpgrade } = props;
return ( return (
<div className="mt-12 flex h-full w-full flex-col items-center"> <div className="mt-6 max-w-3xl">
<CreditCard className="mb-3 h-12 w-12 text-gray-300" /> <h2 className="mb-6 text-2xl font-bold text-black">Subscription Details</h2>
<h3 className="mb-3 text-xl font-semibold text-black">
<div className="overflow-hidden rounded-lg bg-white shadow-sm">
<div className="p-6">
<div className="flex flex-col items-center text-center">
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-gray-100">
<CreditCard className="h-8 w-8 text-gray-500" />
</div>
<h3 className="mt-4 text-xl font-semibold text-black">
No Active Subscription No Active Subscription
</h3> </h3>
<p className="text-balance text-gray-700"> <p className="mt-2 max-w-md text-balance text-gray-600">
Unlock pro benefits by upgrading to a subscription Unlock premium benefits by upgrading to a subscription
</p> </p>
<div className="my-8 flex flex-col gap-2"> <div className="mt-6 w-full max-w-md rounded-lg border border-gray-200 bg-gray-50 p-4">
<h4 className="mb-3 font-medium text-gray-800">Premium Benefits</h4>
<div className="flex flex-col gap-3">
{perks.map((perk) => ( {perks.map((perk) => (
<p className="textsm flex items-center text-gray-600" key={perk.text}> <div className="flex items-center gap-2 text-gray-700" key={perk.text}>
<perk.icon className="mr-2 h-4 w-4 text-gray-500" /> <CheckCircle className="h-5 w-5 text-green-500" />
{perk.text} <span>{perk.text}</span>
</p> </div>
))} ))}
</div> </div>
</div>
<button <button
onClick={onUpgrade} onClick={onUpgrade}
className="inline-flex items-center justify-center rounded-lg bg-black px-6 py-2.5 text-sm font-medium text-white transition-colors hover:opacity-80 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2" className="mt-6 inline-flex items-center justify-center rounded-md bg-black px-6 py-2.5 text-sm font-medium text-white shadow-sm transition-colors hover:bg-black/80 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
> >
Upgrade Account Upgrade Account
</button> </button>
</div> </div>
</div>
</div>
</div>
); );
} }

Loading…
Cancel
Save