Perf improvements and billing updates
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||
|
||||
export default GlobalLoader;
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export default withI18n(GlobalLoader);
|
||||
|
||||
@@ -26,6 +26,7 @@ export function TeamAccountCheckoutForm(params: { accountId: string }) {
|
||||
if (checkoutToken) {
|
||||
return (
|
||||
<EmbeddedCheckout
|
||||
load
|
||||
checkoutToken={checkoutToken}
|
||||
provider={billingConfig.provider}
|
||||
/>
|
||||
|
||||
@@ -16,11 +16,18 @@ interface SessionPageProps {
|
||||
};
|
||||
}
|
||||
|
||||
const LazyEmbeddedCheckout = dynamic(async () => {
|
||||
const { EmbeddedCheckout } = await import('@kit/billing-gateway/components');
|
||||
const LazyEmbeddedCheckout = dynamic(
|
||||
async () => {
|
||||
const { EmbeddedCheckout } = await import(
|
||||
'@kit/billing-gateway/components'
|
||||
);
|
||||
|
||||
return EmbeddedCheckout;
|
||||
});
|
||||
return EmbeddedCheckout;
|
||||
},
|
||||
{
|
||||
ssr: false,
|
||||
},
|
||||
);
|
||||
|
||||
async function ReturnStripeSessionPage({ searchParams }: SessionPageProps) {
|
||||
const { customerEmail, checkoutToken } = await loadCheckoutSession(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||
|
||||
export default GlobalLoader;
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export default withI18n(GlobalLoader);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||
|
||||
export default GlobalLoader;
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export default withI18n(GlobalLoader);
|
||||
|
||||
@@ -44,7 +44,7 @@ export function SiteNavigation() {
|
||||
<>
|
||||
<div className={'hidden items-center lg:flex'}>
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList className={'space-x-2.5'}>
|
||||
<NavigationMenuList className={'space-x-3'}>
|
||||
<NavigationMenuItem>
|
||||
<Link className={className} href={links.Blog.path}>
|
||||
{links.Blog.label}
|
||||
|
||||
@@ -9,7 +9,7 @@ import Post from '~/(marketing)/blog/_components/post';
|
||||
import appConfig from '~/config/app.config';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export async function generateMetadata({
|
||||
export function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
@@ -49,7 +49,7 @@ export async function generateMetadata({
|
||||
};
|
||||
}
|
||||
|
||||
async function BlogPost({ params }: { params: { slug: string } }) {
|
||||
function BlogPost({ params }: { params: { slug: string } }) {
|
||||
const post = allPosts.find((post) => post.slug === params.slug);
|
||||
|
||||
if (!post) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import type { Post as PostType } from 'contentlayer/generated';
|
||||
|
||||
import { Mdx } from '@kit/ui/mdx';
|
||||
|
||||
import { PostHeader } from './post-header';
|
||||
|
||||
const Mdx = dynamic(() =>
|
||||
import('@kit/ui/mdx').then((mod) => ({ default: mod.Mdx })),
|
||||
);
|
||||
|
||||
export const Post: React.FC<{
|
||||
post: PostType;
|
||||
content: string;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||
|
||||
export default GlobalLoader;
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export default withI18n(GlobalLoader);
|
||||
|
||||
5
apps/web/app/loading.tsx
Normal file
5
apps/web/app/loading.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { GlobalLoader } from '@kit/ui/global-loader';
|
||||
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
export default withI18n(GlobalLoader);
|
||||
@@ -2,6 +2,7 @@ import Link from 'next/link';
|
||||
|
||||
import { ArrowLeft } from 'lucide-react';
|
||||
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { Heading } from '@kit/ui/heading';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
@@ -14,10 +15,16 @@ export const metadata = {
|
||||
title: `Page not found - ${appConfig.name}`,
|
||||
};
|
||||
|
||||
const NotFoundPage = () => {
|
||||
const NotFoundPage = async () => {
|
||||
const client = getSupabaseServerComponentClient();
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await client.auth.getSession();
|
||||
|
||||
return (
|
||||
<div className={'flex h-screen flex-1 flex-col'}>
|
||||
<SiteHeader session={null} />
|
||||
<SiteHeader session={session} />
|
||||
|
||||
<div
|
||||
className={
|
||||
|
||||
@@ -143,12 +143,14 @@ function getPatterns() {
|
||||
const supabase = createMiddlewareClient(req, res);
|
||||
const { data, error } = await supabase.auth.getSession();
|
||||
const origin = req.nextUrl.origin;
|
||||
const next = req.nextUrl.pathname;
|
||||
|
||||
// If user is not logged in, redirect to sign in page.
|
||||
if (!data.session || error) {
|
||||
return NextResponse.redirect(
|
||||
new URL(pathsConfig.auth.signIn, origin).href,
|
||||
);
|
||||
const signIn = pathsConfig.auth.signIn;
|
||||
const redirectPath = `${signIn}?next=${next}`;
|
||||
|
||||
return NextResponse.redirect(new URL(redirectPath, origin).href);
|
||||
}
|
||||
|
||||
const requiresMultiFactorAuthentication =
|
||||
|
||||
@@ -3,35 +3,49 @@ import withBundleAnalyzer from '@next/bundle-analyzer';
|
||||
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
|
||||
const INTERNAL_PACKAGES = [
|
||||
'@kit/ui',
|
||||
'@kit/auth',
|
||||
'@kit/accounts',
|
||||
'@kit/team-accounts',
|
||||
'@kit/shared',
|
||||
'@kit/supabase',
|
||||
'@kit/i18n',
|
||||
'@kit/mailers',
|
||||
'@kit/billing',
|
||||
'@kit/billing-gateway',
|
||||
'@kit/stripe',
|
||||
];
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const config = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
/** Enables hot reloading for local packages without a build step */
|
||||
transpilePackages: [
|
||||
'@kit/ui',
|
||||
'@kit/auth',
|
||||
'@kit/accounts',
|
||||
'@kit/team-accounts',
|
||||
'@kit/shared',
|
||||
'@kit/supabase',
|
||||
'@kit/i18n',
|
||||
'@kit/mailers',
|
||||
'@kit/billing',
|
||||
'@kit/billing-gateway',
|
||||
'@kit/stripe',
|
||||
],
|
||||
transpilePackages: INTERNAL_PACKAGES,
|
||||
pageExtensions: ['ts', 'tsx'],
|
||||
images: {
|
||||
remotePatterns: getRemotePatterns(),
|
||||
},
|
||||
experimental: {
|
||||
mdxRs: true,
|
||||
optimizePackageImports: []
|
||||
optimizePackageImports: [
|
||||
'recharts',
|
||||
'lucide-react',
|
||||
'@radix-ui/react-icons',
|
||||
'@radix-ui/react-avatar',
|
||||
'@radix-ui/react-select',
|
||||
'date-fns',
|
||||
...INTERNAL_PACKAGES,
|
||||
],
|
||||
},
|
||||
modularizeImports: {
|
||||
"lucide-react": {
|
||||
transform: "lucide-react/dist/esm/icons/{{ kebabCase member }}",
|
||||
}
|
||||
'lucide-react': {
|
||||
transform: 'lucide-react/dist/esm/icons/{{ kebabCase member }}',
|
||||
},
|
||||
lodash: {
|
||||
transform: 'lodash/{{member}}',
|
||||
},
|
||||
},
|
||||
/** We already do linting and typechecking as separate tasks in CI */
|
||||
eslint: { ignoreDuringBuilds: true },
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
"name": "web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true pnpm run build",
|
||||
"build": "pnpm with-env next build",
|
||||
"clean": "git clean -xdf .next .turbo node_modules",
|
||||
"dev": "pnpm with-env next dev",
|
||||
"dev": "pnpm with-env next dev --turbo",
|
||||
"lint": "next lint",
|
||||
"format": "prettier --check \"**/*.{js,cjs,mjs,ts,tsx,md,json}\"",
|
||||
"start": "pnpm with-env next start",
|
||||
@@ -44,7 +45,7 @@
|
||||
"next-contentlayer": "0.3.4",
|
||||
"react-i18next": "^14.1.0",
|
||||
"date-fns": "^3.2.0",
|
||||
"next": "^14.2.0-canary.41",
|
||||
"next": "canary",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"next-themes": "^0.2.1",
|
||||
"react": "18.2.0",
|
||||
@@ -60,7 +61,7 @@
|
||||
"@kit/prettier-config": "^0.1.0",
|
||||
"@kit/tailwind-config": "^0.1.0",
|
||||
"@kit/tsconfig": "^0.1.0",
|
||||
"@next/bundle-analyzer": "^14.2.0-canary.41",
|
||||
"@next/bundle-analyzer": "canary",
|
||||
"@types/mdx": "^2.0.10",
|
||||
"@types/node": "^20.11.5",
|
||||
"@types/react": "^18.2.48",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowRightIcon } from '@radix-ui/react-icons';
|
||||
import { ArrowUpRight } from 'lucide-react';
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
@@ -15,7 +15,7 @@ export function BillingPortalCard() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Manage your Subscription</CardTitle>
|
||||
<CardTitle>Manage your Billing Details</CardTitle>
|
||||
|
||||
<CardDescription>
|
||||
You can change your plan or cancel your subscription at any time.
|
||||
@@ -23,15 +23,13 @@ export function BillingPortalCard() {
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className={'space-y-2'}>
|
||||
<Button className={'w-full'}>
|
||||
<span>Manage your Billing Settings</span>
|
||||
<ArrowRightIcon className={'ml-2 h-4'} />
|
||||
</Button>
|
||||
<div>
|
||||
<Button>
|
||||
<span>Visit the billing portal</span>
|
||||
|
||||
<p className={'text-sm'}>
|
||||
Visit the billing portal to manage your subscription (update payment
|
||||
method, cancel subscription, etc.)
|
||||
</p>
|
||||
<ArrowUpRight className={'h-4'} />
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||
|
||||
export function CurrentPlanAlert(
|
||||
props: React.PropsWithoutRef<{
|
||||
status: Database['public']['Enums']['subscription_status'];
|
||||
}>,
|
||||
) {
|
||||
let variant: 'success' | 'warning' | 'destructive';
|
||||
let text: string;
|
||||
let title: string;
|
||||
|
||||
switch (props.status) {
|
||||
case 'active':
|
||||
variant = 'success';
|
||||
title = 'Active';
|
||||
text = 'Your subscription is active';
|
||||
break;
|
||||
case 'trialing':
|
||||
variant = 'success';
|
||||
title = 'Trial';
|
||||
text = 'You are currently on a trial';
|
||||
break;
|
||||
case 'past_due':
|
||||
variant = 'destructive';
|
||||
title = 'Past Due';
|
||||
text = 'Your subscription payment is past due';
|
||||
break;
|
||||
case 'canceled':
|
||||
variant = 'destructive';
|
||||
title = 'Canceled';
|
||||
text = 'You have canceled your subscription';
|
||||
break;
|
||||
case 'unpaid':
|
||||
variant = 'destructive';
|
||||
title = 'Unpaid';
|
||||
text = 'Your subscription payment is unpaid';
|
||||
break;
|
||||
case 'incomplete':
|
||||
variant = 'warning';
|
||||
title = 'Incomplete';
|
||||
text = 'We are processing your subscription payment';
|
||||
break;
|
||||
case 'incomplete_expired':
|
||||
variant = 'destructive';
|
||||
title = 'Incomplete Expired';
|
||||
text = 'Your subscription payment has expired';
|
||||
break;
|
||||
case 'paused':
|
||||
variant = 'warning';
|
||||
title = 'Paused';
|
||||
text = 'Your subscription is paused';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert variant={variant}>
|
||||
<AlertTitle>{title}</AlertTitle>
|
||||
|
||||
<AlertDescription>{text}</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import { Badge } from '@kit/ui/badge';
|
||||
|
||||
export function CurrentPlanBadge(
|
||||
props: React.PropsWithoutRef<{
|
||||
status: Database['public']['Enums']['subscription_status'];
|
||||
}>,
|
||||
) {
|
||||
let variant: 'success' | 'warning' | 'destructive';
|
||||
let text: string;
|
||||
|
||||
switch (props.status) {
|
||||
case 'active':
|
||||
variant = 'success';
|
||||
text = 'Active';
|
||||
break;
|
||||
case 'trialing':
|
||||
variant = 'success';
|
||||
text = 'Trialing';
|
||||
break;
|
||||
case 'past_due':
|
||||
variant = 'destructive';
|
||||
text = 'Past due';
|
||||
break;
|
||||
case 'canceled':
|
||||
variant = 'destructive';
|
||||
text = 'Canceled';
|
||||
break;
|
||||
case 'unpaid':
|
||||
variant = 'destructive';
|
||||
text = 'Unpaid';
|
||||
break;
|
||||
case 'incomplete':
|
||||
variant = 'warning';
|
||||
text = 'Incomplete';
|
||||
break;
|
||||
case 'incomplete_expired':
|
||||
variant = 'destructive';
|
||||
text = 'Incomplete expired';
|
||||
break;
|
||||
case 'paused':
|
||||
variant = 'warning';
|
||||
text = 'Paused';
|
||||
break;
|
||||
}
|
||||
|
||||
return <Badge variant={variant}>{text}</Badge>;
|
||||
}
|
||||
@@ -1,8 +1,15 @@
|
||||
import { formatDate } from 'date-fns';
|
||||
import { BadgeCheck, CheckCircle2 } from 'lucide-react';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { BillingSchema, getProductPlanPairFromId } from '@kit/billing';
|
||||
import { Database } from '@kit/supabase/database';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from '@kit/ui/accordion';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -11,6 +18,10 @@ import {
|
||||
CardTitle,
|
||||
} from '@kit/ui/card';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { CurrentPlanAlert } from './current-plan-alert';
|
||||
import { CurrentPlanBadge } from './current-plan-badge';
|
||||
|
||||
export function CurrentPlanCard({
|
||||
subscription,
|
||||
@@ -27,41 +38,103 @@ export function CurrentPlanCard({
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{product.name}</CardTitle>
|
||||
<CardTitle>Your Plan</CardTitle>
|
||||
|
||||
<CardDescription>{product.description}</CardDescription>
|
||||
<CardDescription>
|
||||
You can change your plan or cancel your subscription at any time.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className={'space-y-4 text-sm'}>
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Your Current Plan: <span>{plan.name}</span>
|
||||
<CardContent className={'space-y-2.5 text-sm'}>
|
||||
<div className={'flex flex-col space-y-1'}>
|
||||
<div className={'flex items-center space-x-2 text-lg font-semibold'}>
|
||||
<BadgeCheck
|
||||
className={
|
||||
's-6 fill-green-500 text-white dark:fill-white dark:text-black'
|
||||
}
|
||||
/>
|
||||
<span>{product.name}</span>
|
||||
<CurrentPlanBadge status={subscription.status} />
|
||||
</div>
|
||||
|
||||
<div className={'text-muted-foreground'}>
|
||||
Renews every {subscription.interval} at{' '}
|
||||
<span>{product.currency}</span> <span>{plan.price}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className={'font-semibold'}>
|
||||
Your Subscription is currently <span>{subscription.status}</span>
|
||||
</div>
|
||||
<CurrentPlanAlert status={subscription.status} />
|
||||
</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>
|
||||
<div>
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="features">
|
||||
<AccordionTrigger>Plan details</AccordionTrigger>
|
||||
|
||||
<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>
|
||||
<AccordionContent className="space-y-2.5">
|
||||
<If condition={subscription.status === 'trialing'}>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Your trial ends on</span>
|
||||
|
||||
<div className={'text-muted-foreground'}>
|
||||
<span>
|
||||
{subscription.trial_ends_at
|
||||
? formatDate(subscription.trial_ends_at, 'P')
|
||||
: ''}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={subscription.cancel_at_period_end}>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">
|
||||
Your subscription will be cancelled at the end of the
|
||||
period
|
||||
</span>
|
||||
|
||||
<div className={'text-muted-foreground'}>
|
||||
<span>
|
||||
{formatDate(subscription.period_ends_at ?? '', 'P')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<If condition={!subscription.cancel_at_period_end}>
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span className="font-medium">Your next bill</span>
|
||||
|
||||
<div className={'text-muted-foreground'}>
|
||||
Your next bill is for {product.currency} {plan.price} on{' '}
|
||||
<span>
|
||||
{formatDate(subscription.period_ends_at ?? '', 'P')}
|
||||
</span>{' '}
|
||||
</div>
|
||||
</div>
|
||||
</If>
|
||||
|
||||
<div className="flex flex-col space-y-1">
|
||||
<span className="font-medium">Features</span>
|
||||
|
||||
<ul>
|
||||
{product.features.map((item) => {
|
||||
return (
|
||||
<li key={item} className="flex items-center space-x-0.5">
|
||||
<CheckCircle2 className="h-4 text-green-500" />
|
||||
<span>
|
||||
<Trans i18nKey={item} defaults={item} />
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -15,10 +15,22 @@ export function EmbeddedCheckout(
|
||||
provider: BillingProvider;
|
||||
onClose?: () => void;
|
||||
}>,
|
||||
) {
|
||||
return (
|
||||
<LazyCheckout onClose={props.onClose} checkoutToken={props.checkoutToken} />
|
||||
);
|
||||
}
|
||||
|
||||
function LazyCheckout(
|
||||
props: React.PropsWithChildren<{
|
||||
checkoutToken: string;
|
||||
provider: BillingProvider;
|
||||
onClose?: () => void;
|
||||
}>,
|
||||
) {
|
||||
const CheckoutComponent = useMemo(
|
||||
() => memo(loadCheckoutComponent(props.provider)),
|
||||
[],
|
||||
[props.provider],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -69,7 +81,7 @@ function buildLazyComponent<
|
||||
) {
|
||||
let LoadedComponent: ReturnType<typeof lazy> | null = null;
|
||||
|
||||
const LazyComponent = forwardRef((props, ref) => {
|
||||
const LazyComponent = forwardRef(function LazyDynamicComponent(props, ref) {
|
||||
if (!LoadedComponent) {
|
||||
LoadedComponent = lazy(load);
|
||||
}
|
||||
|
||||
@@ -105,5 +105,5 @@ export function getProductPlanPairFromId(
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
throw new Error(`Plan with ID ${planId} not found`);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
|
||||
import type { Provider } from '@supabase/supabase-js';
|
||||
|
||||
@@ -27,13 +27,17 @@ export function SignInMethodsContainer(props: {
|
||||
oAuth: Provider[];
|
||||
};
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const nextPath = useSearchParams().get('next') ?? props.paths.home;
|
||||
|
||||
const redirectUrl = new URL(
|
||||
props.paths.callback,
|
||||
isBrowser() ? window?.location.origin : '',
|
||||
).toString();
|
||||
|
||||
const router = useRouter();
|
||||
const onSignIn = () => router.replace(props.paths.home);
|
||||
const onSignIn = () => {
|
||||
router.replace(nextPath);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -23,7 +23,7 @@ export function initializeI18nClient(
|
||||
.use(
|
||||
resourcesToBackend(async (language, namespace, callback) => {
|
||||
const data = await i18nResolver(language, namespace);
|
||||
console.log(data);
|
||||
|
||||
return callback(null, data);
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ export class StripeWebhookHandlerService
|
||||
async verifyWebhookSignature(request: Request) {
|
||||
const body = await request.clone().text();
|
||||
const signatureKey = `stripe-signature`;
|
||||
const signature = request.headers.get(signatureKey) as string;
|
||||
const signature = request.headers.get(signatureKey)!;
|
||||
|
||||
const { STRIPE_WEBHOOK_SECRET } = StripeServerEnvSchema.parse({
|
||||
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
|
||||
|
||||
@@ -28,6 +28,7 @@ function AuthRedirectListener({
|
||||
useEffect(() => {
|
||||
// keep this running for the whole session unless the component was unmounted
|
||||
const listener = client.auth.onAuthStateChange((_, user) => {
|
||||
console.log(_, user);
|
||||
// log user out if user is falsy
|
||||
// and if the current path is a private route
|
||||
const shouldRedirectUser = !user && isPrivateRoute(pathName);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-accordion": "1.1.2",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
@@ -44,7 +45,6 @@
|
||||
"@kit/prettier-config": "0.1.0",
|
||||
"@kit/tailwind-config": "0.1.0",
|
||||
"@kit/tsconfig": "0.1.0",
|
||||
"@tanstack/react-table": "^8.11.3",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"date-fns": "^3.2.0",
|
||||
@@ -67,6 +67,7 @@
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
"exports": {
|
||||
"./accordion": "./src/shadcn/accordion.tsx",
|
||||
"./avatar": "./src/shadcn/avatar.tsx",
|
||||
"./button": "./src/shadcn/button.tsx",
|
||||
"./calendar": "./src/shadcn/calendar.tsx",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { cn } from './utils';
|
||||
|
||||
const NavigationContainer: React.FC<{
|
||||
className?: string;
|
||||
}> = ({ children, className }) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(`dark:border-dark-800 border-b border-gray-50`, className)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavigationContainer;
|
||||
@@ -1,124 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useContext } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
import Trans from '@/components/app/Trans';
|
||||
import { cva } from 'class-variance-authority';
|
||||
|
||||
import isRouteActive from '@kit/generic/is-route-active';
|
||||
|
||||
import { NavigationMenuContext } from './navigation-menu-context';
|
||||
import { cn } from './utils';
|
||||
|
||||
interface Link {
|
||||
path: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const NavigationMenuItem: React.FC<{
|
||||
link: Link;
|
||||
depth?: number;
|
||||
disabled?: boolean;
|
||||
shallow?: boolean;
|
||||
className?: string;
|
||||
}> = ({ link, disabled, shallow, depth, ...props }) => {
|
||||
const pathName = usePathname() ?? '';
|
||||
const active = isRouteActive(link.path, pathName, depth ?? 3);
|
||||
const menuProps = useContext(NavigationMenuContext);
|
||||
const label = link.label;
|
||||
|
||||
const itemClassName = getNavigationMenuItemClassBuilder()({
|
||||
active,
|
||||
...menuProps,
|
||||
});
|
||||
|
||||
const className = cn(itemClassName, props.className ?? ``);
|
||||
|
||||
return (
|
||||
<li className={className}>
|
||||
<Link
|
||||
className={
|
||||
'justify-center transition-transform duration-500 lg:justify-start'
|
||||
}
|
||||
aria-disabled={disabled}
|
||||
href={disabled ? '' : link.path}
|
||||
shallow={shallow ?? active}
|
||||
>
|
||||
<Trans i18nKey={label} defaults={label} />
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavigationMenuItem;
|
||||
|
||||
function getNavigationMenuItemClassBuilder() {
|
||||
return cva(
|
||||
[
|
||||
`flex items-center justify-center font-medium lg:justify-start rounded-md text-sm transition colors transform *:active:translate-y-[2px]`,
|
||||
'*:p-1 *:lg:px-2.5 *:s-full *:flex *:items-center',
|
||||
'aria-disabled:cursor-not-allowed aria-disabled:opacity-50',
|
||||
],
|
||||
{
|
||||
compoundVariants: [
|
||||
// not active - shared
|
||||
{
|
||||
active: false,
|
||||
className: `font-medium hover:underline`,
|
||||
},
|
||||
// active - shared
|
||||
{
|
||||
active: true,
|
||||
className: `font-semibold`,
|
||||
},
|
||||
// active - pill
|
||||
{
|
||||
active: true,
|
||||
pill: true,
|
||||
className: `bg-gray-50 text-gray-800 dark:bg-primary-300/10`,
|
||||
},
|
||||
// not active - pill
|
||||
{
|
||||
active: false,
|
||||
pill: true,
|
||||
className: `hover:bg-gray-50 active:bg-gray-100 text-gray-500 dark:text-gray-300 dark:hover:bg-background dark:active:bg-dark-900/90`,
|
||||
},
|
||||
// not active - bordered
|
||||
{
|
||||
active: false,
|
||||
bordered: true,
|
||||
className: `hover:bg-gray-50 active:bg-gray-100 dark:active:bg-dark-800 dark:hover:bg-dark/90 transition-colors rounded-lg border-transparent`,
|
||||
},
|
||||
// active - bordered
|
||||
{
|
||||
active: true,
|
||||
bordered: true,
|
||||
className: `top-[0.4rem] border-b-[0.25rem] rounded-none border-primary bg-transparent pb-[0.55rem] text-primary-700 dark:text-white`,
|
||||
},
|
||||
// active - secondary
|
||||
{
|
||||
active: true,
|
||||
secondary: true,
|
||||
className: `bg-transparent font-semibold`,
|
||||
},
|
||||
],
|
||||
variants: {
|
||||
active: {
|
||||
true: ``,
|
||||
},
|
||||
pill: {
|
||||
true: `[&>*]:py-2`,
|
||||
},
|
||||
bordered: {
|
||||
true: `relative h-10`,
|
||||
},
|
||||
secondary: {
|
||||
true: ``,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import type { NavigationMenuProps } from './navigation-menu';
|
||||
|
||||
export const NavigationMenuContext = createContext<NavigationMenuProps>({});
|
||||
@@ -1,49 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import type { PropsWithChildren } from 'react';
|
||||
|
||||
import { cva } from 'class-variance-authority';
|
||||
|
||||
import { NavigationMenuContext } from './navigation-menu-context';
|
||||
|
||||
type Vertical = {
|
||||
vertical?: boolean;
|
||||
};
|
||||
|
||||
type Bordered = {
|
||||
bordered?: boolean;
|
||||
};
|
||||
|
||||
type Pill = {
|
||||
pill?: boolean;
|
||||
};
|
||||
|
||||
export type NavigationMenuProps = Vertical & (Bordered | Pill);
|
||||
|
||||
function NavigationMenu(props: PropsWithChildren<NavigationMenuProps>) {
|
||||
const className = getNavigationMenuClassBuilder()(props);
|
||||
|
||||
return (
|
||||
<ul className={className}>
|
||||
<NavigationMenuContext.Provider value={props}>
|
||||
{props.children}
|
||||
</NavigationMenuContext.Provider>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavigationMenu;
|
||||
|
||||
function getNavigationMenuClassBuilder() {
|
||||
return cva(['w-full dark:text-gray-300 items-center flex-wrap flex'], {
|
||||
variants: {
|
||||
vertical: {
|
||||
true: `flex items-start justify-between space-x-2
|
||||
lg:flex-col lg:justify-start lg:space-x-0 lg:space-y-1.5 [&>li>a]:w-full`,
|
||||
},
|
||||
bordered: {
|
||||
true: `lg:space-x-3 border-b border-gray-100 dark:border-dark-800 pb-1.5`,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -21,7 +21,6 @@ function Spinner(
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
|
||||
58
packages/ui/src/shadcn/accordion.tsx
Normal file
58
packages/ui/src/shadcn/accordion.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import { ChevronDownIcon } from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from '../utils';
|
||||
|
||||
const Accordion = AccordionPrimitive.Root;
|
||||
|
||||
const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AccordionPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn('border-b', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AccordionItem.displayName = 'AccordionItem';
|
||||
|
||||
const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Header className="flex">
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
));
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
|
||||
|
||||
const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn('pb-4 pt-0', className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
));
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
@@ -17,7 +17,7 @@ const badgeVariants = cva(
|
||||
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
||||
outline: 'text-foreground',
|
||||
success:
|
||||
'border-transparent bg-green-50 text-green-500 dark:bg-transparent',
|
||||
'border-transparent bg-green-50 text-green-500 dark:bg-green-500/20',
|
||||
warning:
|
||||
'border-transparent bg-orange-50 text-orange-500 dark:bg-transparent',
|
||||
info: 'border-transparent bg-blue-50 text-blue-500 dark:bg-transparent',
|
||||
|
||||
153
pnpm-lock.yaml
generated
153
pnpm-lock.yaml
generated
@@ -88,7 +88,7 @@ importers:
|
||||
version: 5.28.6(react@18.2.0)
|
||||
'@tanstack/react-query-next-experimental':
|
||||
specifier: ^5.28.6
|
||||
version: 5.28.6(@tanstack/react-query@5.28.6)(next@14.2.0-canary.41)(react@18.2.0)
|
||||
version: 5.28.6(@tanstack/react-query@5.28.6)(next@14.2.0-canary.43)(react@18.2.0)
|
||||
'@tanstack/react-table':
|
||||
specifier: ^8.11.3
|
||||
version: 8.14.0(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -100,7 +100,7 @@ importers:
|
||||
version: 3.6.0
|
||||
edge-csrf:
|
||||
specifier: ^1.0.9
|
||||
version: 1.0.9(next@14.2.0-canary.41)
|
||||
version: 1.0.9(next@14.2.0-canary.43)
|
||||
i18next:
|
||||
specifier: ^23.10.1
|
||||
version: 23.10.1
|
||||
@@ -108,17 +108,17 @@ importers:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
next:
|
||||
specifier: ^14.2.0-canary.41
|
||||
version: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: canary
|
||||
version: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next-contentlayer:
|
||||
specifier: 0.3.4
|
||||
version: 0.3.4(contentlayer@0.3.4)(esbuild@0.19.11)(next@14.2.0-canary.41)(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 0.3.4(contentlayer@0.3.4)(esbuild@0.19.11)(next@14.2.0-canary.43)(react-dom@18.2.0)(react@18.2.0)
|
||||
next-sitemap:
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3(next@14.2.0-canary.41)
|
||||
version: 4.2.3(next@14.2.0-canary.43)
|
||||
next-themes:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1(next@14.2.0-canary.41)(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 0.2.1(next@14.2.0-canary.43)(react-dom@18.2.0)(react@18.2.0)
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
@@ -163,8 +163,8 @@ importers:
|
||||
specifier: ^0.1.0
|
||||
version: link:../../tooling/typescript
|
||||
'@next/bundle-analyzer':
|
||||
specifier: ^14.2.0-canary.41
|
||||
version: 14.2.0-canary.41
|
||||
specifier: canary
|
||||
version: 14.2.0-canary.43
|
||||
'@types/mdx':
|
||||
specifier: ^2.0.10
|
||||
version: 2.0.11
|
||||
@@ -333,6 +333,10 @@ importers:
|
||||
version: link:../../../tooling/typescript
|
||||
|
||||
packages/features/admin:
|
||||
dependencies:
|
||||
'@kit/ui':
|
||||
specifier: 0.1.0
|
||||
version: link:../../ui
|
||||
devDependencies:
|
||||
'@kit/eslint-config':
|
||||
specifier: 0.2.0
|
||||
@@ -568,6 +572,9 @@ importers:
|
||||
|
||||
packages/ui:
|
||||
dependencies:
|
||||
'@radix-ui/react-accordion':
|
||||
specifier: 1.1.2
|
||||
version: 1.1.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-alert-dialog':
|
||||
specifier: ^1.0.5
|
||||
version: 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
@@ -619,6 +626,9 @@ importers:
|
||||
'@radix-ui/react-tooltip':
|
||||
specifier: 1.0.7
|
||||
version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@tanstack/react-table':
|
||||
specifier: ^8.10.7
|
||||
version: 8.14.0(react-dom@18.2.0)(react@18.2.0)
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
@@ -659,9 +669,6 @@ importers:
|
||||
'@kit/tsconfig':
|
||||
specifier: 0.1.0
|
||||
version: link:../../tooling/typescript
|
||||
'@tanstack/react-table':
|
||||
specifier: ^8.11.3
|
||||
version: 8.14.0(react-dom@18.2.0)(react@18.2.0)
|
||||
'@types/react':
|
||||
specifier: ^18.2.48
|
||||
version: 18.2.67
|
||||
@@ -1770,8 +1777,8 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@next/bundle-analyzer@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-1+PP3XaC3lz0oE49D0jxGsiEJZOmwlDgqV3yantl64vXRNX8Ae3Gsk1KcDhp7JHKKPvFx4AF13/LF48sbH0zkw==}
|
||||
/@next/bundle-analyzer@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-5GYBb99OLnmg5xZDrUUD0ILB/gJDN4MxJTG5fU5JQXIDc6Ew+jJgMzjdqptJduvlExorAWNNpQnjdnRlnZCQfg==}
|
||||
dependencies:
|
||||
webpack-bundle-analyzer: 4.10.1
|
||||
transitivePeerDependencies:
|
||||
@@ -1791,8 +1798,8 @@ packages:
|
||||
resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==}
|
||||
dev: false
|
||||
|
||||
/@next/env@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-6bd8zNDEferyJ9qkJrCB0pTgGFaJ9XttMI+uj5jrSeQ88kxsgPcoOFqBEMDtDOEzWqi+17B29alThei0Cmw0dA==}
|
||||
/@next/env@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-jBjfC5J053shwv+g4kplFG+iH1TqWwMtLCIpDSplOmRDLdGeai6s3oKmWIxd+MbG5ETSZOl1vCN5A3nMgGkXfg==}
|
||||
dev: false
|
||||
|
||||
/@next/eslint-plugin-next@14.1.4:
|
||||
@@ -1833,8 +1840,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-arm64@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-cplMeo/uQcfSHwZH2naB87IWzJouOSPXFQqRk1/nwuQNPxLFT2xO2v7zP4L4W98qukvLylFxWQhqpIQqZnohIA==}
|
||||
/@next/swc-darwin-arm64@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-M9Asj8J6GMVNdMRnDnR+hELiyjgaHSUYAZz4M7ro5Vd1X8wpg3jygd/RnkTv+hhHn3rqwV9jWyZ4xdyG3SORrg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
@@ -1860,8 +1867,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-x64@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-mnqPeUMFUg73DXEsNOxrKXy09ikcErLeFEzYVqn5XwaewVyqny9xwf8f02BYBcLEBrmk565xkocnTs7su45qqA==}
|
||||
/@next/swc-darwin-x64@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-3BQ5FirbYZgXAFOCUynDr/Sl0fcFfEiLiDVdGMaJO7754fuWJShcj5tODiFC2B7MgLsVkri/84prBzsjkg76jA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
@@ -1887,8 +1894,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-gnu@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-ns0/YS9yqqS71h4xZNGn+IDZC7q3fLrF9mIaZ3aXhkHpXfeyjACOAEC6/0l0E49w4VkPv0XK64aRvsxsZfFr9g==}
|
||||
/@next/swc-linux-arm64-gnu@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-VoCLYDTD2bkLsUkT0bACplrdpTw+IBKdFr5ih85atePrujCz6dMPUxeNMwH9aYL7r3PgzH6dR30r0Y5TFwUUSg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@@ -1914,8 +1921,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-musl@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-22nsQMLgJH3ZbxbgQmiwGbFtW8KtDRQJU8OSyWcO8MFTgPdL3IcRd/lTsR5r9qliosoGgHzFSYDAq/7M5I/w0Q==}
|
||||
/@next/swc-linux-arm64-musl@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-8c35oylAS4Ggu155txTpOv7VG4BzG8BTluVbUZuaneZwsZi6VTbjVKMVnLYmmdcdRkkvRgPc83oUr2HGxwxFBw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
@@ -1941,8 +1948,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-gnu@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-ZkcPQk+SV+i06i0k/UVmXKk+k70yKIwtTPrWl7JpeJ/Wc7sWoRqNCdpFqP227oOsy6dM0NKqJTEOATBYAefQLg==}
|
||||
/@next/swc-linux-x64-gnu@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-PHy7clJ+ChZzNJ3c9A2IrWJN4aNa+FZ+v39XNdcjdkdhPvwu1QSvtirWSbxqKpAqgA/3sMhAGCvwOx6yeBs4Ug==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@@ -1968,8 +1975,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-musl@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-1Uofz0Bkec63oN7Xj9lHGevCqxZJrr6pruPx5JUb613CYqUVCVj6JA8H2JutYYwgcbwstjdA+9He37HlW1FGTw==}
|
||||
/@next/swc-linux-x64-musl@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-pvma+GKwkDEzhQRrwl9P4oGu9A9NGJH/Za+SG/XwWph2i78+4OMDCKrmKEJ1T5BE6Bgo+Emfhdy8TmfqHPQQCg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
@@ -1995,8 +2002,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-arm64-msvc@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-gMzwgq1ZnKwxYx2I4qhuRtaGZ/6WZD8XV0cObnaWXiu8O7NCK1kEKa6+IWy+Manax5qwamHKzWND5uKbeddToQ==}
|
||||
/@next/swc-win32-arm64-msvc@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-b1npBheIu7/BgMZTCFkuNYv0Q/N9u6+7MYY5xjZDVIutW8ut2V93JZqeC2SYWFm03I+LNdYjplRhn3TVerz9Xg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
@@ -2022,8 +2029,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-ia32-msvc@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-U72bjcHUUoRToFTAouUqK9y/PaiKVo4rDX5/RwzIZThPghfHf5ALG6DYiw64sKWSRXSfFOv9DzhofjK1+CIgSA==}
|
||||
/@next/swc-win32-ia32-msvc@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-1bZDCGyQzvdRNxVUUhsjBZOzBEEoQlh1r91ifjUz9nhcFYOlmP6IplPMjaLmG+GJMUiI36j5svdPYO3LP08b8g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
@@ -2049,8 +2056,8 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-x64-msvc@14.2.0-canary.41:
|
||||
resolution: {integrity: sha512-cBgEDwdxfyv9bBoo5dKBtfxd7S7Dv3dTRKYx7agprJ3BdGc8gXs2zdi08lR/fBU0kjpsC4gw/tg5p+IDkuZUaw==}
|
||||
/@next/swc-win32-x64-msvc@14.2.0-canary.43:
|
||||
resolution: {integrity: sha512-pU9gjLmp4yjYzBqCGa5bQ0iyJ5D73IRITEUFKrjZPi0XHUbFLrhcaaCsnVgMO4xfOQJgS7ODuQB7N0iPk7/EMw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -2386,6 +2393,35 @@ packages:
|
||||
'@babel/runtime': 7.24.1
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.1
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.67)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.67)(react@18.2.0)
|
||||
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.67)(react@18.2.0)
|
||||
'@radix-ui/react-id': 1.0.1(@types/react@18.2.67)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.67)(react@18.2.0)
|
||||
'@types/react': 18.2.67
|
||||
'@types/react-dom': 18.2.22
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-alert-dialog@1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.67)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA==}
|
||||
peerDependencies:
|
||||
@@ -4187,7 +4223,7 @@ packages:
|
||||
/@tanstack/query-core@5.28.6:
|
||||
resolution: {integrity: sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA==}
|
||||
|
||||
/@tanstack/react-query-next-experimental@5.28.6(@tanstack/react-query@5.28.6)(next@14.2.0-canary.41)(react@18.2.0):
|
||||
/@tanstack/react-query-next-experimental@5.28.6(@tanstack/react-query@5.28.6)(next@14.2.0-canary.43)(react@18.2.0):
|
||||
resolution: {integrity: sha512-KHTR1nGChTXk/kELit2gaqF3cQuN68F5UJv0377Gz5DnllPnBegja6if2W9KtKxm3Z1xP0j8LQXplqlqny2SYw==}
|
||||
peerDependencies:
|
||||
'@tanstack/react-query': ^5.28.6
|
||||
@@ -4195,7 +4231,7 @@ packages:
|
||||
react: ^18.0.0
|
||||
dependencies:
|
||||
'@tanstack/react-query': 5.28.6(react@18.2.0)
|
||||
next: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
@@ -4217,10 +4253,12 @@ packages:
|
||||
'@tanstack/table-core': 8.14.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@tanstack/table-core@8.14.0:
|
||||
resolution: {integrity: sha512-wDhpKJahGHWhmRt4RxtV3pES63CoeadljGWS/xeS9OJr1HBl2NB+OO44ht3sxDH5j5TRDAbQzC0NvSlsUfn7lQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/@tootallnate/quickjs-emscripten@0.23.0:
|
||||
resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
|
||||
@@ -6033,12 +6071,12 @@ packages:
|
||||
/eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
/edge-csrf@1.0.9(next@14.2.0-canary.41):
|
||||
/edge-csrf@1.0.9(next@14.2.0-canary.43):
|
||||
resolution: {integrity: sha512-3F89YTh42UDdISr3s9AEcgJDLi4ysgjGfnybzF0LuZGaG2W31h1ZwgWwEQBLMj04lAklcP4XHZYi7vk9o8zcbg==}
|
||||
peerDependencies:
|
||||
next: ^13.0.0 || ^14.0.0
|
||||
dependencies:
|
||||
next: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/editorconfig@1.0.4:
|
||||
@@ -8784,7 +8822,7 @@ packages:
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dev: true
|
||||
|
||||
/next-contentlayer@0.3.4(contentlayer@0.3.4)(esbuild@0.19.11)(next@14.2.0-canary.41)(react-dom@18.2.0)(react@18.2.0):
|
||||
/next-contentlayer@0.3.4(contentlayer@0.3.4)(esbuild@0.19.11)(next@14.2.0-canary.43)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-UtUCwgAl159KwfhNaOwyiI7Lg6sdioyKMeh+E7jxx0CJ29JuXGxBEYmCI6+72NxFGIFZKx8lvttbbQhbnYWYSw==}
|
||||
peerDependencies:
|
||||
contentlayer: 0.3.4
|
||||
@@ -8795,7 +8833,7 @@ packages:
|
||||
'@contentlayer/core': 0.3.4(esbuild@0.19.11)
|
||||
'@contentlayer/utils': 0.3.4
|
||||
contentlayer: 0.3.4(esbuild@0.19.11)
|
||||
next: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
@@ -8805,7 +8843,7 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/next-sitemap@4.2.3(next@14.2.0-canary.41):
|
||||
/next-sitemap@4.2.3(next@14.2.0-canary.43):
|
||||
resolution: {integrity: sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==}
|
||||
engines: {node: '>=14.18'}
|
||||
hasBin: true
|
||||
@@ -8816,17 +8854,17 @@ packages:
|
||||
'@next/env': 13.5.6
|
||||
fast-glob: 3.3.2
|
||||
minimist: 1.2.8
|
||||
next: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/next-themes@0.2.1(next@14.2.0-canary.41)(react-dom@18.2.0)(react@18.2.0):
|
||||
/next-themes@0.2.1(next@14.2.0-canary.43)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
|
||||
peerDependencies:
|
||||
next: '*'
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
dependencies:
|
||||
next: 14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
next: 14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
@@ -8909,22 +8947,25 @@ packages:
|
||||
- babel-plugin-macros
|
||||
dev: false
|
||||
|
||||
/next@14.2.0-canary.41(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-jqNSTq1COP04WXpj88Bzt8kkCLXFNpCU4tHzQrICAMVWeNtHTZpK2WPR8560SWBw614bW2qHYY85k0tez3YLiA==}
|
||||
/next@14.2.0-canary.43(@opentelemetry/api@1.8.0)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-tL5fxsleOuRS7Momx5wRwkCOPLybQKwgJnpzgMGVReQs+kA9lkQiBANvlYdAsrvZ3vjzx2H+9mSqKDcKaC8UXQ==}
|
||||
engines: {node: '>=18.17.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@opentelemetry/api': ^1.1.0
|
||||
'@playwright/test': ^1.41.2
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
sass: ^1.3.0
|
||||
peerDependenciesMeta:
|
||||
'@opentelemetry/api':
|
||||
optional: true
|
||||
'@playwright/test':
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@next/env': 14.2.0-canary.41
|
||||
'@next/env': 14.2.0-canary.43
|
||||
'@opentelemetry/api': 1.8.0
|
||||
'@swc/helpers': 0.5.5
|
||||
busboy: 1.6.0
|
||||
@@ -8935,15 +8976,15 @@ packages:
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
styled-jsx: 5.1.1(react@18.2.0)
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 14.2.0-canary.41
|
||||
'@next/swc-darwin-x64': 14.2.0-canary.41
|
||||
'@next/swc-linux-arm64-gnu': 14.2.0-canary.41
|
||||
'@next/swc-linux-arm64-musl': 14.2.0-canary.41
|
||||
'@next/swc-linux-x64-gnu': 14.2.0-canary.41
|
||||
'@next/swc-linux-x64-musl': 14.2.0-canary.41
|
||||
'@next/swc-win32-arm64-msvc': 14.2.0-canary.41
|
||||
'@next/swc-win32-ia32-msvc': 14.2.0-canary.41
|
||||
'@next/swc-win32-x64-msvc': 14.2.0-canary.41
|
||||
'@next/swc-darwin-arm64': 14.2.0-canary.43
|
||||
'@next/swc-darwin-x64': 14.2.0-canary.43
|
||||
'@next/swc-linux-arm64-gnu': 14.2.0-canary.43
|
||||
'@next/swc-linux-arm64-musl': 14.2.0-canary.43
|
||||
'@next/swc-linux-x64-gnu': 14.2.0-canary.43
|
||||
'@next/swc-linux-x64-musl': 14.2.0-canary.43
|
||||
'@next/swc-win32-arm64-msvc': 14.2.0-canary.43
|
||||
'@next/swc-win32-ia32-msvc': 14.2.0-canary.43
|
||||
'@next/swc-win32-x64-msvc': 14.2.0-canary.43
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
@@ -19,7 +19,6 @@ const config = {
|
||||
'^@supabase/supabase-js$',
|
||||
'^@supabase/gotrue-js$',
|
||||
'<THIRD_PARTY_MODULES>',
|
||||
'^@packages/(.*)$',
|
||||
'^@kit/(.*)$',
|
||||
'^~/(.*)$', // app-specific imports
|
||||
'^[./]', // relative imports
|
||||
|
||||
@@ -3,7 +3,7 @@ import { fontFamily } from 'tailwindcss/defaultTheme';
|
||||
|
||||
export default {
|
||||
darkMode: ['class'],
|
||||
content: ['../../packages/**/*.{ts,tsx}', '../../apps/**/*.{ts,tsx}'],
|
||||
content: ['../../packages/**/*.tsx', '../../apps/**/*.tsx'],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"noUncheckedIndexedAccess": true
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
42
turbo.json
42
turbo.json
@@ -1,31 +1,49 @@
|
||||
{
|
||||
"$schema": "https://turborepo.org/schema.json",
|
||||
"globalDependencies": ["**/.env"],
|
||||
"globalDependencies": [
|
||||
"**/.env"
|
||||
],
|
||||
"pipeline": {
|
||||
"topo": {
|
||||
"dependsOn": ["^topo"]
|
||||
"dependsOn": [
|
||||
"^topo"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".next/**", "!.next/cache/**", "next-env.d.ts"],
|
||||
"dotEnv": [".env.production.local", ".env.local", ".env.production", ".env"]
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
".next/**",
|
||||
"!.next/cache/**",
|
||||
"next-env.d.ts"
|
||||
]
|
||||
},
|
||||
"dev": {
|
||||
"persistent": true,
|
||||
"cache": false,
|
||||
"dotEnv": [".env.development.local", ".env.local", ".env.development", ".env"]
|
||||
"cache": false
|
||||
},
|
||||
"format": {
|
||||
"outputs": ["node_modules/.cache/.prettiercache"],
|
||||
"outputs": [
|
||||
"node_modules/.cache/.prettiercache"
|
||||
],
|
||||
"outputMode": "new-only"
|
||||
},
|
||||
"lint": {
|
||||
"dependsOn": ["^topo"],
|
||||
"outputs": ["node_modules/.cache/.eslintcache"]
|
||||
"dependsOn": [
|
||||
"^topo"
|
||||
],
|
||||
"outputs": [
|
||||
"node_modules/.cache/.eslintcache"
|
||||
]
|
||||
},
|
||||
"typecheck": {
|
||||
"dependsOn": ["^topo"],
|
||||
"outputs": ["node_modules/.cache/tsbuildinfo.json"]
|
||||
"dependsOn": [
|
||||
"^topo"
|
||||
],
|
||||
"outputs": [
|
||||
"node_modules/.cache/tsbuildinfo.json"
|
||||
]
|
||||
},
|
||||
"clean": {
|
||||
"cache": false
|
||||
|
||||
Reference in New Issue
Block a user