From 7579ee9a2cd5387a5a5943a72aa6b36d569da0a2 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Wed, 27 Mar 2024 15:07:15 +0800 Subject: [PATCH] Refactor authentication flow and improve code organization The update implemented a redirect functionality in the multi-factor authentication flow for a better user experience. It also involved a refactoring of some parts of the code, substituting direct routing paths with path configs for easier future modifications. Import statements were adjusted for better code organization and readability. --- .../[account]/_components/dashboard-demo.tsx | 4 +- .../team-account-checkout-form.tsx | 1 - apps/web/app/(marketing)/blog/[slug]/page.tsx | 4 +- .../docs/_lib/build-documentation-tree.ts | 4 +- apps/web/app/(marketing)/pricing/page.tsx | 2 +- apps/web/app/auth/callback/route.ts | 80 ++++--------------- apps/web/app/join/page.tsx | 36 +-------- apps/web/config/auth.config.ts | 2 +- apps/web/config/feature-flags.config.ts | 2 +- apps/web/config/paths.config.ts | 4 +- apps/web/next.config.mjs | 4 +- apps/web/public/locales/en/billing.json | 2 +- .../src/components/current-plan-card.tsx | 4 +- .../src/components/embedded-checkout.tsx | 2 +- .../billing-gateway/src/components/index.ts | 1 + .../src/components/plan-picker.tsx | 8 +- .../src/components/pricing-table.tsx | 3 +- packages/features/admin/package.json | 8 +- ...AdminDashboard.tsx => admin-dashboard.tsx} | 4 +- .../{AdminGuard.tsx => admin-guard.tsx} | 13 +-- .../{AdminHeader.tsx => admin-header.tsx} | 5 +- .../{AdminSidebar.tsx => admin-sidebar.tsx} | 6 +- packages/features/admin/src/index.ts | 1 + .../features/admin/src/lib/is-super-admin.ts | 19 +++++ .../services/account-invitations.service.ts | 2 +- packages/shared/src/utils.ts | 7 ++ packages/supabase/src/hooks/use-supabase.ts | 5 +- packages/ui/src/makerkit/data-table.tsx | 2 +- .../ui/src/makerkit/image-upload-input.tsx | 5 ++ packages/ui/src/makerkit/is-route-active.ts | 2 +- .../ui/src/makerkit/mdx/mdx-components.tsx | 2 +- packages/ui/src/makerkit/mdx/mdx-renderer.tsx | 1 + pnpm-lock.yaml | 9 +++ 33 files changed, 103 insertions(+), 151 deletions(-) rename packages/{billing => billing-gateway}/src/components/pricing-table.tsx (99%) rename packages/features/admin/src/components/{AdminDashboard.tsx => admin-dashboard.tsx} (96%) rename packages/features/admin/src/components/{AdminGuard.tsx => admin-guard.tsx} (52%) rename packages/features/admin/src/components/{AdminHeader.tsx => admin-header.tsx} (88%) rename packages/features/admin/src/components/{AdminSidebar.tsx => admin-sidebar.tsx} (87%) create mode 100644 packages/features/admin/src/index.ts create mode 100644 packages/features/admin/src/lib/is-super-admin.ts diff --git a/apps/web/app/(dashboard)/home/[account]/_components/dashboard-demo.tsx b/apps/web/app/(dashboard)/home/[account]/_components/dashboard-demo.tsx index 466c9fda7..20b325776 100644 --- a/apps/web/app/(dashboard)/home/[account]/_components/dashboard-demo.tsx +++ b/apps/web/app/(dashboard)/home/[account]/_components/dashboard-demo.tsx @@ -206,7 +206,9 @@ function generateDemoData() { }); } - return [data, data[data.length - 1].value] as [typeof data, string]; + const lastValue = data[data.length - 1]?.value; + + return [data, lastValue] as [typeof data, string]; } function Chart( diff --git a/apps/web/app/(dashboard)/home/[account]/billing/_components/team-account-checkout-form.tsx b/apps/web/app/(dashboard)/home/[account]/billing/_components/team-account-checkout-form.tsx index c1495949c..dc39b3cce 100644 --- a/apps/web/app/(dashboard)/home/[account]/billing/_components/team-account-checkout-form.tsx +++ b/apps/web/app/(dashboard)/home/[account]/billing/_components/team-account-checkout-form.tsx @@ -26,7 +26,6 @@ export function TeamAccountCheckoutForm(params: { accountId: string }) { if (checkoutToken) { return ( diff --git a/apps/web/app/(marketing)/blog/[slug]/page.tsx b/apps/web/app/(marketing)/blog/[slug]/page.tsx index 1bc901833..9ce0c447f 100644 --- a/apps/web/app/(marketing)/blog/[slug]/page.tsx +++ b/apps/web/app/(marketing)/blog/[slug]/page.tsx @@ -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 function generateMetadata({ +export async function generateMetadata({ params, }: { params: { slug: string }; @@ -17,7 +17,7 @@ export function generateMetadata({ const post = allPosts.find((post) => post.slug === params.slug); if (!post) { - return; + notFound(); } const { title, date, description, image, slug } = post; diff --git a/apps/web/app/(marketing)/docs/_lib/build-documentation-tree.ts b/apps/web/app/(marketing)/docs/_lib/build-documentation-tree.ts index f0d654616..ca624f2f9 100644 --- a/apps/web/app/(marketing)/docs/_lib/build-documentation-tree.ts +++ b/apps/web/app/(marketing)/docs/_lib/build-documentation-tree.ts @@ -5,8 +5,8 @@ import type { DocumentationPage } from 'contentlayer/generated'; export interface ProcessedDocumentationPage extends DocumentationPage { collapsible: boolean; pathSegments: string[]; - nextPage: ProcessedDocumentationPage | DocumentationPage | null; - previousPage: ProcessedDocumentationPage | DocumentationPage | null; + nextPage: ProcessedDocumentationPage | DocumentationPage | undefined; + previousPage: ProcessedDocumentationPage | DocumentationPage | undefined; children: DocsTree; } diff --git a/apps/web/app/(marketing)/pricing/page.tsx b/apps/web/app/(marketing)/pricing/page.tsx index e9474bce3..53de5a32e 100644 --- a/apps/web/app/(marketing)/pricing/page.tsx +++ b/apps/web/app/(marketing)/pricing/page.tsx @@ -1,4 +1,4 @@ -import { PricingTable } from '@kit/billing/components/pricing-table'; +import { PricingTable } from '@kit/billing-gateway/components'; import { SitePageHeader } from '~/(marketing)/_components/site-page-header'; import billingConfig from '~/config/billing.config'; diff --git a/apps/web/app/auth/callback/route.ts b/apps/web/app/auth/callback/route.ts index b853041d9..125b40e04 100644 --- a/apps/web/app/auth/callback/route.ts +++ b/apps/web/app/auth/callback/route.ts @@ -6,30 +6,37 @@ import { getSupabaseRouteHandlerClient } from '@kit/supabase/route-handler-clien import pathsConfig from '~/config/paths.config'; +const defaultNextUrl = pathsConfig.app.home; + export async function GET(request: NextRequest) { const requestUrl = new URL(request.url); const searchParams = requestUrl.searchParams; const authCode = searchParams.get('code'); - const inviteCode = searchParams.get('inviteCode'); const error = searchParams.get('error'); - const nextUrl = searchParams.get('next') ?? pathsConfig.app.home; + const nextUrlPathFromParams = searchParams.get('next'); + const inviteToken = searchParams.get('invite_token'); - let userId: string | undefined = undefined; + let nextUrl = nextUrlPathFromParams ?? defaultNextUrl; + + // if we have an invite token, we redirect to the join team page + // instead of the default next url. This is because the user is trying + // to join a team and we want to make sure they are redirected to the + // correct page. + if (inviteToken) { + nextUrl = `${pathsConfig.app.joinTeam}?invite_token=${inviteToken}`; + } if (authCode) { const client = getSupabaseRouteHandlerClient(); try { - const { error, data } = - await client.auth.exchangeCodeForSession(authCode); + const { error } = await client.auth.exchangeCodeForSession(authCode); // if we have an error, we redirect to the error page if (error) { return onError({ error: error.message }); } - - userId = data.user.id; } catch (error) { Logger.error( { @@ -42,34 +49,6 @@ export async function GET(request: NextRequest) { return onError({ error: message as string }); } - - if (inviteCode && userId) { - try { - Logger.info( - { - userId, - inviteCode, - }, - `Attempting to accept user invite...`, - ); - - // if we have an invite code, we accept the invite - await acceptInviteFromEmailLink({ inviteCode, userId }); - } catch (error) { - Logger.error( - { - userId, - inviteCode, - error, - }, - `An error occurred while accepting user invite`, - ); - - const message = error instanceof Error ? error.message : error; - - return onError({ error: message as string }); - } - } } if (error) { @@ -79,37 +58,6 @@ export async function GET(request: NextRequest) { return redirect(nextUrl); } -/** - * @name acceptInviteFromEmailLink - * @description If we find an invite code, we try to accept the invite - * received from the email link method - * @param params - */ -async function acceptInviteFromEmailLink(params: { - inviteCode: string; - userId: string | undefined; -}) { - if (!params.userId) { - Logger.error(params, `Attempted to accept invite, but no user id provided`); - - return; - } - - Logger.info(params, `Found invite code. Accepting invite...`); - - await acceptInviteToOrganization( - getSupabaseRouteHandlerClient({ - admin: true, - }), - { - code: params.inviteCode, - userId: params.userId, - }, - ); - - Logger.info(params, `Invite successfully accepted`); -} - function onError({ error }: { error: string }) { const errorMessage = getAuthErrorMessage(error); diff --git a/apps/web/app/join/page.tsx b/apps/web/app/join/page.tsx index 03dbbf067..889e62117 100644 --- a/apps/web/app/join/page.tsx +++ b/apps/web/app/join/page.tsx @@ -1,9 +1,6 @@ import { notFound } from 'next/navigation'; import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client'; -import { Heading } from '@kit/ui/heading'; -import { If } from '@kit/ui/if'; -import { Trans } from '@kit/ui/trans'; import { withI18n } from '~/lib/i18n/with-i18n'; @@ -25,36 +22,7 @@ async function JoinTeamAccountPage({ searchParams }: Context) { notFound(); } - return ( - <> - - - - -
-

- }} - /> -

- -

- - - -

-
- - ); + return <>; } export default withI18n(JoinTeamAccountPage); @@ -66,7 +34,7 @@ async function getInviteDataFromInviteToken(token: string) { const { data: invitation, error } = await adminClient .from('invitations') - .select('*') + .select() .eq('invite_token', token) .single(); diff --git a/apps/web/config/auth.config.ts b/apps/web/config/auth.config.ts index 3f007d23d..5b0a30a19 100644 --- a/apps/web/config/auth.config.ts +++ b/apps/web/config/auth.config.ts @@ -24,7 +24,7 @@ const authConfig = AuthConfigSchema.parse({ magicLink: false, oAuth: ['google'], }, -}); +} satisfies z.infer); export default authConfig; diff --git a/apps/web/config/feature-flags.config.ts b/apps/web/config/feature-flags.config.ts index 411985b68..9dde03afd 100644 --- a/apps/web/config/feature-flags.config.ts +++ b/apps/web/config/feature-flags.config.ts @@ -36,7 +36,7 @@ const featuresFlagConfig = FeatureFlagsSchema.parse({ process.env.NEXT_PUBLIC_ENABLE_ORGANIZATION_BILLING, false, ), -}); +} satisfies z.infer); export default featuresFlagConfig; diff --git a/apps/web/config/paths.config.ts b/apps/web/config/paths.config.ts index e2b58f9a2..ad0bf1201 100644 --- a/apps/web/config/paths.config.ts +++ b/apps/web/config/paths.config.ts @@ -19,6 +19,7 @@ const PathsSchema = z.object({ accountBilling: z.string().min(1), accountMembers: z.string().min(1), accountBillingReturn: z.string().min(1), + joinTeam: z.string().min(1), }), }); @@ -41,7 +42,8 @@ const pathsConfig = PathsSchema.parse({ accountBilling: `/home/[account]/billing`, accountMembers: `/home/[account]/members`, accountBillingReturn: `/home/[account]/billing/return`, + joinTeam: '/join', }, -}); +} satisfies z.infer); export default pathsConfig; diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 9fc8a0540..014dd1a71 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -57,11 +57,13 @@ export default withBundleAnalyzer({ })(config); function getRemotePatterns() { - // add here the remote patterns for your images + /** @type {import('next').NextConfig['remotePatterns']} */ + // add here the remote patterns for your images const remotePatterns = []; if (SUPABASE_URL) { const hostname = new URL(SUPABASE_URL).hostname; + remotePatterns.push({ protocol: 'https', hostname, diff --git a/apps/web/public/locales/en/billing.json b/apps/web/public/locales/en/billing.json index ba21370d7..36649d70f 100644 --- a/apps/web/public/locales/en/billing.json +++ b/apps/web/public/locales/en/billing.json @@ -2,7 +2,7 @@ "subscriptionTabSubheading": "Manage your Subscription and Billing", "planCardTitle": "Your Plan", "planCardDescription": "Below are the details of your current plan. You can change your plan or cancel your subscription at any time.", - "planRenewal": "Renews every {{interval}} at {{currency}} {{price}}", + "planRenewal": "Renews every {{interval}} at {{price}}", "planDetails": "Plan Details", "checkout": "Proceed to Checkout", "trialEndsOn": "Your trial ends on", diff --git a/packages/billing-gateway/src/components/current-plan-card.tsx b/packages/billing-gateway/src/components/current-plan-card.tsx index 2913ebee3..74c5164b7 100644 --- a/packages/billing-gateway/src/components/current-plan-card.tsx +++ b/packages/billing-gateway/src/components/current-plan-card.tsx @@ -3,6 +3,7 @@ import { BadgeCheck, CheckCircle2 } from 'lucide-react'; import { z } from 'zod'; import { BillingSchema, getProductPlanPairFromId } from '@kit/billing'; +import { formatCurrency } from '@kit/shared/utils'; import { Database } from '@kit/supabase/database'; import { Accordion, @@ -65,8 +66,7 @@ export function CurrentPlanCard({ i18nKey="billing:planRenewal" values={{ interval: subscription.interval, - currency: product.currency, - price: plan.price, + price: formatCurrency(product.currency, plan.price), }} /> diff --git a/packages/billing-gateway/src/components/embedded-checkout.tsx b/packages/billing-gateway/src/components/embedded-checkout.tsx index 07d8b4719..f5288d7c8 100644 --- a/packages/billing-gateway/src/components/embedded-checkout.tsx +++ b/packages/billing-gateway/src/components/embedded-checkout.tsx @@ -11,7 +11,7 @@ export function EmbeddedCheckout( props: React.PropsWithChildren<{ checkoutToken: string; provider: BillingProvider; - onClose: () => void; + onClose?: () => void; }>, ) { const CheckoutComponent = useMemo( diff --git a/packages/billing-gateway/src/components/index.ts b/packages/billing-gateway/src/components/index.ts index e9f9e8b3b..0ba655853 100644 --- a/packages/billing-gateway/src/components/index.ts +++ b/packages/billing-gateway/src/components/index.ts @@ -3,3 +3,4 @@ export * from './current-plan-card'; export * from './embedded-checkout'; export * from './billing-session-status'; export * from './billing-portal-card'; +export * from './pricing-table'; diff --git a/packages/billing-gateway/src/components/plan-picker.tsx b/packages/billing-gateway/src/components/plan-picker.tsx index 038055eff..2c0bd4c8d 100644 --- a/packages/billing-gateway/src/components/plan-picker.tsx +++ b/packages/billing-gateway/src/components/plan-picker.tsx @@ -6,6 +6,7 @@ import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { BillingSchema } from '@kit/billing'; +import { formatCurrency } from '@kit/shared/utils'; import { Button } from '@kit/ui/button'; import { Form, @@ -233,10 +234,3 @@ function Price(props: React.PropsWithChildren) { ); } - -function formatCurrency(currencyCode: string, value: string) { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: currencyCode, - }).format(value); -} diff --git a/packages/billing/src/components/pricing-table.tsx b/packages/billing-gateway/src/components/pricing-table.tsx similarity index 99% rename from packages/billing/src/components/pricing-table.tsx rename to packages/billing-gateway/src/components/pricing-table.tsx index 01f23866f..b3c123cbc 100644 --- a/packages/billing/src/components/pricing-table.tsx +++ b/packages/billing-gateway/src/components/pricing-table.tsx @@ -7,14 +7,13 @@ import Link from 'next/link'; import { CheckCircle, Sparkles } from 'lucide-react'; import { z } from 'zod'; +import { BillingSchema, getPlanIntervals } from '@kit/billing'; import { Button } from '@kit/ui/button'; import { Heading } from '@kit/ui/heading'; import { If } from '@kit/ui/if'; import { Trans } from '@kit/ui/trans'; import { cn } from '@kit/ui/utils'; -import { BillingSchema, getPlanIntervals } from '../create-billing-schema'; - type Config = z.infer; interface Paths { diff --git a/packages/features/admin/package.json b/packages/features/admin/package.json index bd0172f85..0e416ae0b 100644 --- a/packages/features/admin/package.json +++ b/packages/features/admin/package.json @@ -17,10 +17,14 @@ "@kit/prettier-config": "0.1.0", "@kit/tailwind-config": "0.1.0", "@kit/tsconfig": "0.1.0", - "@kit/ui": "*" + "@kit/ui": "*", + "@kit/supabase": "*", + "@supabase/supabase-js": "2.40.0", + "lucide-react": "^0.363.0" }, "exports": { - ".": "./src/index.ts" + ".": "./src/index.ts", + "./components/*": "./src/components/*" }, "eslintConfig": { "root": true, diff --git a/packages/features/admin/src/components/AdminDashboard.tsx b/packages/features/admin/src/components/admin-dashboard.tsx similarity index 96% rename from packages/features/admin/src/components/AdminDashboard.tsx rename to packages/features/admin/src/components/admin-dashboard.tsx index 110bacff2..594d27463 100644 --- a/packages/features/admin/src/components/AdminDashboard.tsx +++ b/packages/features/admin/src/components/admin-dashboard.tsx @@ -7,7 +7,7 @@ interface Data { trialSubscriptions: number; } -function AdminDashboard({ +export function AdminDashboard({ data, }: React.PropsWithChildren<{ data: Data; @@ -70,8 +70,6 @@ function AdminDashboard({ ); } -export default AdminDashboard; - function Figure(props: React.PropsWithChildren) { return
{props.children}
; } diff --git a/packages/features/admin/src/components/AdminGuard.tsx b/packages/features/admin/src/components/admin-guard.tsx similarity index 52% rename from packages/features/admin/src/components/AdminGuard.tsx rename to packages/features/admin/src/components/admin-guard.tsx index d5e35ed56..6a255a27d 100644 --- a/packages/features/admin/src/components/AdminGuard.tsx +++ b/packages/features/admin/src/components/admin-guard.tsx @@ -1,22 +1,23 @@ import { notFound } from 'next/navigation'; -import isUserSuperAdmin from '../../../app/admin/utils/is-user-super-admin'; +import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client'; + +import { isSuperAdmin } from '../lib/is-super-admin'; type LayoutOrPageComponent = React.ComponentType; -function AdminGuard( +export function AdminGuard( Component: LayoutOrPageComponent, ) { return async function AdminGuardServerComponentWrapper(params: Params) { - const isAdmin = await isUserSuperAdmin(); + const client = getSupabaseServerComponentClient(); + const isUserSuperAdmin = await isSuperAdmin(client); // if the user is not a super-admin, we redirect to a 404 - if (!isAdmin) { + if (!isUserSuperAdmin) { notFound(); } return ; }; } - -export default AdminGuard; diff --git a/packages/features/admin/src/components/AdminHeader.tsx b/packages/features/admin/src/components/admin-header.tsx similarity index 88% rename from packages/features/admin/src/components/AdminHeader.tsx rename to packages/features/admin/src/components/admin-header.tsx index fe54d9890..1bc62a9b9 100644 --- a/packages/features/admin/src/components/AdminHeader.tsx +++ b/packages/features/admin/src/components/admin-header.tsx @@ -5,11 +5,10 @@ import { ArrowLeft } from 'lucide-react'; import { Button } from '@kit/ui/button'; import { PageHeader } from '@kit/ui/page'; -function AdminHeader({ +export function AdminHeader({ children, paths, }: React.PropsWithChildren<{ - appHome: string; paths: { appHome: string; }; @@ -28,5 +27,3 @@ function AdminHeader({ ); } - -export default AdminHeader; diff --git a/packages/features/admin/src/components/AdminSidebar.tsx b/packages/features/admin/src/components/admin-sidebar.tsx similarity index 87% rename from packages/features/admin/src/components/AdminSidebar.tsx rename to packages/features/admin/src/components/admin-sidebar.tsx index 48aca4079..73e166b05 100644 --- a/packages/features/admin/src/components/AdminSidebar.tsx +++ b/packages/features/admin/src/components/admin-sidebar.tsx @@ -1,10 +1,8 @@ -'use client'; - import { Home, User, Users } from 'lucide-react'; import { Sidebar, SidebarContent, SidebarItem } from '@kit/ui/sidebar'; -function AdminSidebar(props: { Logo: React.ReactNode }) { +export function AdminSidebar(props: { Logo: React.ReactNode }) { return ( {props.Logo} @@ -28,5 +26,3 @@ function AdminSidebar(props: { Logo: React.ReactNode }) { ); } - -export default AdminSidebar; diff --git a/packages/features/admin/src/index.ts b/packages/features/admin/src/index.ts new file mode 100644 index 000000000..427d99962 --- /dev/null +++ b/packages/features/admin/src/index.ts @@ -0,0 +1 @@ +export * from './lib/is-super-admin'; diff --git a/packages/features/admin/src/lib/is-super-admin.ts b/packages/features/admin/src/lib/is-super-admin.ts new file mode 100644 index 000000000..f6f610561 --- /dev/null +++ b/packages/features/admin/src/lib/is-super-admin.ts @@ -0,0 +1,19 @@ +import { SupabaseClient } from '@supabase/supabase-js'; + +import { Database } from '@kit/supabase/database'; + +export async function isSuperAdmin(client: SupabaseClient) { + const { data, error } = await client.auth.getUser(); + + if (error) { + throw error; + } + + if (!data.user) { + return false; + } + + const appMetadata = data.user.app_metadata; + + return appMetadata?.role === 'super-admin'; +} diff --git a/packages/features/team-accounts/src/services/account-invitations.service.ts b/packages/features/team-accounts/src/services/account-invitations.service.ts index fd5887590..cded7f533 100644 --- a/packages/features/team-accounts/src/services/account-invitations.service.ts +++ b/packages/features/team-accounts/src/services/account-invitations.service.ts @@ -72,7 +72,7 @@ export class AccountInvitationsService { role: params.role, }) .match({ - id: params.id, + id: params.invitationId, }); if (error) { diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index d90aa3e9f..f440452f7 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -1,3 +1,10 @@ export function isBrowser() { return typeof window !== 'undefined'; } + +export function formatCurrency(currencyCode: string, value: string | number) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: currencyCode, + }).format(Number(value)); +} diff --git a/packages/supabase/src/hooks/use-supabase.ts b/packages/supabase/src/hooks/use-supabase.ts index 251384dcb..19ff67a11 100644 --- a/packages/supabase/src/hooks/use-supabase.ts +++ b/packages/supabase/src/hooks/use-supabase.ts @@ -1,8 +1,7 @@ import { useMemo } from 'react'; import { getSupabaseBrowserClient } from '../clients/browser.client'; -import { Database } from '../database.types'; -export function useSupabase() { - return useMemo(() => getSupabaseBrowserClient(), []); +export function useSupabase() { + return useMemo(() => getSupabaseBrowserClient(), []); } diff --git a/packages/ui/src/makerkit/data-table.tsx b/packages/ui/src/makerkit/data-table.tsx index 5fd88ce30..f96d63677 100644 --- a/packages/ui/src/makerkit/data-table.tsx +++ b/packages/ui/src/makerkit/data-table.tsx @@ -36,7 +36,7 @@ import { TableRow, } from '../shadcn/table'; import { cn } from '../utils'; -import Trans from './trans'; +import { Trans } from './trans'; interface ReactTableProps { data: T[]; diff --git a/packages/ui/src/makerkit/image-upload-input.tsx b/packages/ui/src/makerkit/image-upload-input.tsx index 8bf5d4728..774aa53e6 100644 --- a/packages/ui/src/makerkit/image-upload-input.tsx +++ b/packages/ui/src/makerkit/image-upload-input.tsx @@ -49,6 +49,11 @@ export const ImageUploadInput = forwardRef, Props>( if (files?.length) { const file = files[0]; + + if (!file) { + return; + } + const data = URL.createObjectURL(file); setState({ diff --git a/packages/ui/src/makerkit/is-route-active.ts b/packages/ui/src/makerkit/is-route-active.ts index 018647aed..98898e618 100644 --- a/packages/ui/src/makerkit/is-route-active.ts +++ b/packages/ui/src/makerkit/is-route-active.ts @@ -14,7 +14,7 @@ export default function isRouteActive( depth: number, ) { // we remove any eventual query param from the route's URL - const currentRoutePath = currentRoute.split('?')[0]; + const currentRoutePath = currentRoute.split('?')[0] ?? ''; if (!isRoot(currentRoutePath) && isRoot(targetLink)) { return false; diff --git a/packages/ui/src/makerkit/mdx/mdx-components.tsx b/packages/ui/src/makerkit/mdx/mdx-components.tsx index 963f7f2fb..c046d3ac0 100644 --- a/packages/ui/src/makerkit/mdx/mdx-components.tsx +++ b/packages/ui/src/makerkit/mdx/mdx-components.tsx @@ -2,7 +2,7 @@ import { forwardRef } from 'react'; import Image from 'next/image'; -import { cn } from '../../shadcn'; +import { cn } from '../../utils'; import { LazyRender } from '../lazy-render'; const NextImage: React.FC<{ diff --git a/packages/ui/src/makerkit/mdx/mdx-renderer.tsx b/packages/ui/src/makerkit/mdx/mdx-renderer.tsx index 30e800048..73931d83e 100644 --- a/packages/ui/src/makerkit/mdx/mdx-renderer.tsx +++ b/packages/ui/src/makerkit/mdx/mdx-renderer.tsx @@ -2,6 +2,7 @@ import type { MDXComponents } from 'mdx/types'; import { getMDXComponent } from 'next-contentlayer/hooks'; import Components from './mdx-components'; +// @ts-ignore import styles from './mdx-renderer.module.css'; export function Mdx({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47404b492..f5f965f79 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -319,6 +319,9 @@ importers: '@kit/prettier-config': specifier: 0.1.0 version: link:../../../tooling/prettier + '@kit/supabase': + specifier: '*' + version: link:../../supabase '@kit/tailwind-config': specifier: 0.1.0 version: link:../../../tooling/tailwind @@ -328,6 +331,12 @@ importers: '@kit/ui': specifier: '*' version: link:../../ui + '@supabase/supabase-js': + specifier: 2.40.0 + version: 2.40.0 + lucide-react: + specifier: ^0.363.0 + version: 0.363.0(react@18.2.0) packages/features/auth: devDependencies: