Refactor code and improve usage of package dependencies
This commit updates the naming convention of icons from Lucide-React, moving some package dependencies to "peerDependencies" in 'team-accounts', 'admin' and 'auth'. Additionally, it includes tweaks to the development server command in apps/web package.json and adds a logger reference to the shared package. Furthermore, cleanup work has been performed within the features and UI packages, and new scripts to interact with Stripe have been added to the root package.json.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowRightIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@kit/ui/card';
|
||||
|
||||
export function BillingPortalCard() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Manage your Subscription</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
You can change your plan or cancel your subscription at any time.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className={'space-y-2'}>
|
||||
<Button className={'w-full'}>
|
||||
<span>Manage your Billing Settings</span>
|
||||
<ArrowRightIcon className={'ml-2 h-4'} />
|
||||
</Button>
|
||||
|
||||
<p className={'text-sm'}>
|
||||
Visit the billing portal to manage your subscription (update payment
|
||||
method, cancel subscription, etc.)
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import { CheckIcon, ChevronRightIcon } from 'lucide-react';
|
||||
import { Check, ChevronRight } from 'lucide-react';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
@@ -55,9 +55,9 @@ function SuccessSessionStatus({
|
||||
'flex flex-col items-center justify-center space-y-4 text-center'
|
||||
}
|
||||
>
|
||||
<CheckIcon
|
||||
<Check
|
||||
className={
|
||||
'w-16 rounded-full bg-green-500 p-1 text-white ring-8' +
|
||||
'h-16 w-16 rounded-full bg-green-500 p-1 text-white ring-8' +
|
||||
' ring-green-500/30 dark:ring-green-500/50'
|
||||
}
|
||||
/>
|
||||
@@ -87,7 +87,7 @@ function SuccessSessionStatus({
|
||||
<Trans i18nKey={'subscription:checkoutSuccessBackButton'} />
|
||||
</span>
|
||||
|
||||
<ChevronRightIcon className={'h-4'} />
|
||||
<ChevronRight className={'h-4'} />
|
||||
</span>
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -1 +1,68 @@
|
||||
export function CurrentPlanCard(props: React.PropsWithChildren<{}>) {}
|
||||
import { formatDate } from 'date-fns';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { BillingSchema, getProductPlanPairFromId } from '@kit/billing';
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@kit/ui/card';
|
||||
import { If } from '@kit/ui/if';
|
||||
|
||||
export function CurrentPlanCard({
|
||||
subscription,
|
||||
config,
|
||||
}: React.PropsWithChildren<{
|
||||
subscription: Database['public']['Tables']['subscriptions']['Row'];
|
||||
config: z.infer<typeof BillingSchema>;
|
||||
}>) {
|
||||
const { plan, product } = getProductPlanPairFromId(
|
||||
config,
|
||||
subscription.variant_id,
|
||||
);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{product.name}</CardTitle>
|
||||
|
||||
<CardDescription>{product.description}</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className={'space-y-4 text-sm'}>
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Your Current Plan: <span>{plan.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Your Subscription is currently <span>{subscription.status}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<If condition={subscription.cancel_at_period_end}>
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Cancellation Date:{' '}
|
||||
<span>{formatDate(subscription.period_ends_at, 'P')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={!subscription.cancel_at_period_end}>
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Next Billing Date:{' '}
|
||||
<span>{formatDate(subscription.period_ends_at, 'P')}</span>{' '}
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { lazy } from 'react';
|
||||
import { Suspense, forwardRef, lazy, memo, useMemo } from 'react';
|
||||
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import { LoadingOverlay } from '@kit/ui/loading-overlay';
|
||||
|
||||
type BillingProvider = Database['public']['Enums']['billing_provider'];
|
||||
|
||||
const Fallback = (
|
||||
<LoadingOverlay fullPage={false}>Loading Checkout...</LoadingOverlay>
|
||||
);
|
||||
|
||||
export function EmbeddedCheckout(
|
||||
props: React.PropsWithChildren<{
|
||||
checkoutToken: string;
|
||||
@@ -11,7 +16,10 @@ export function EmbeddedCheckout(
|
||||
onClose?: () => void;
|
||||
}>,
|
||||
) {
|
||||
const CheckoutComponent = loadCheckoutComponent(props.provider);
|
||||
const CheckoutComponent = useMemo(
|
||||
() => memo(loadCheckoutComponent(props.provider)),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<CheckoutComponent
|
||||
@@ -24,10 +32,12 @@ export function EmbeddedCheckout(
|
||||
function loadCheckoutComponent(provider: BillingProvider) {
|
||||
switch (provider) {
|
||||
case 'stripe': {
|
||||
return lazy(() => {
|
||||
return import('@kit/stripe/components').then((c) => ({
|
||||
default: c.StripeCheckout,
|
||||
}));
|
||||
return buildLazyComponent(() => {
|
||||
return import('@kit/stripe/components').then(({ StripeCheckout }) => {
|
||||
return {
|
||||
default: StripeCheckout,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,3 +53,33 @@ function loadCheckoutComponent(provider: BillingProvider) {
|
||||
throw new Error(`Unsupported provider: ${provider as string}`);
|
||||
}
|
||||
}
|
||||
|
||||
function buildLazyComponent<
|
||||
Cmp extends React.ComponentType<
|
||||
React.PropsWithChildren<{
|
||||
onClose?: (() => unknown) | undefined;
|
||||
checkoutToken: string;
|
||||
}>
|
||||
>,
|
||||
>(
|
||||
load: () => Promise<{
|
||||
default: Cmp;
|
||||
}>,
|
||||
fallback = Fallback,
|
||||
) {
|
||||
let LoadedComponent: ReturnType<typeof lazy> | null = null;
|
||||
|
||||
const LazyComponent = forwardRef((props, ref) => {
|
||||
if (!LoadedComponent) {
|
||||
LoadedComponent = lazy(load);
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LoadedComponent {...props} ref={ref} />
|
||||
</Suspense>
|
||||
);
|
||||
});
|
||||
|
||||
return memo(LazyComponent);
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from './plan-picker';
|
||||
export * from './current-plan-card';
|
||||
export * from './embedded-checkout';
|
||||
export * from './billing-session-status';
|
||||
export * from './billing-portal-card';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { ArrowRightIcon } from 'lucide-react';
|
||||
import { ArrowRight } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -212,7 +212,7 @@ export function PlanPicker(
|
||||
) : (
|
||||
<>
|
||||
<span>Proceed to payment</span>
|
||||
<ArrowRightIcon className={'ml-2 h-4 w-4'} />
|
||||
<ArrowRight className={'ml-2 h-4 w-4'} />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user