Skip to content

Commit

Permalink
feat: upgrade to Clerk v5 and use Clerk's Core 2
Browse files Browse the repository at this point in the history
  • Loading branch information
ixartz committed May 10, 2024
1 parent 2e6ff12 commit a92cef0
Show file tree
Hide file tree
Showing 13 changed files with 258 additions and 352 deletions.
426 changes: 146 additions & 280 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"prepare": "husky"
},
"dependencies": {
"@clerk/localizations": "^1.26.16",
"@clerk/nextjs": "^4.29.9",
"@clerk/localizations": "^2.3.1",
"@clerk/nextjs": "^5.0.7",
"@hookform/resolvers": "^3.3.4",
"@libsql/client": "^0.6.0",
"@logtail/pino": "^0.4.21",
Expand Down Expand Up @@ -78,7 +78,7 @@
"@storybook/test": "^7.6.19",
"@storybook/test-runner": "^0.17.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^14.3.1",
"@testing-library/react": "^15.0.7",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.11",
"@types/react": "^18.3.1",
Expand Down
2 changes: 1 addition & 1 deletion src/app/[locale]/(auth)/(center)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { auth } from '@clerk/nextjs';
import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';

export default function CenteredLayout(props: { children: React.ReactNode }) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { SignIn } from '@clerk/nextjs';
import { getTranslations } from 'next-intl/server';

import { getI18nPath } from '@/utils/Helpers';

export async function generateMetadata(props: { params: { locale: string } }) {
const t = await getTranslations({
locale: props.params.locale,
Expand All @@ -13,6 +15,8 @@ export async function generateMetadata(props: { params: { locale: string } }) {
};
}

const SignInPage = () => <SignIn />;
const SignInPage = (props: { params: { locale: string } }) => (
<SignIn path={getI18nPath('/sign-in', props.params.locale)} />
);

export default SignInPage;
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { SignUp } from '@clerk/nextjs';
import { getTranslations } from 'next-intl/server';

import { getI18nPath } from '@/utils/Helpers';

export async function generateMetadata(props: { params: { locale: string } }) {
const t = await getTranslations({
locale: props.params.locale,
Expand All @@ -13,6 +15,8 @@ export async function generateMetadata(props: { params: { locale: string } }) {
};
}

const SignUpPage = () => <SignUp />;
const SignUpPage = (props: { params: { locale: string } }) => (
<SignUp path={getI18nPath('/sign-up', props.params.locale)} />
);

export default SignUpPage;
6 changes: 3 additions & 3 deletions src/app/[locale]/(auth)/dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function DashboardLayout(props: {
<Logo />
</Link>

<div className="ml-5 h-8">
<div className="ml-3">
<OrganizationSwitcher
organizationProfileMode="navigation"
organizationProfileUrl={getI18nPath(
Expand All @@ -55,13 +55,13 @@ export default function DashboardLayout(props: {
</li>

<li>
<ActiveLink href="/dashboard/organization-profile">
<ActiveLink href="/dashboard/organization-profile/organization-members">
{t('members')}
</ActiveLink>
</li>

<li>
<ActiveLink href="/dashboard/organization-profile/organization-settings">
<ActiveLink href="/dashboard/organization-profile">
{t('settings')}
</ActiveLink>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,20 @@ const OrganizationProfilePage = (props: { params: { locale: string } }) => {
description={t('title_bar_description')}
/>

<div className="flex justify-center">
<OrganizationProfile
routing="path"
path={getI18nPath(
'/dashboard/organization-profile',
props.params.locale,
)}
afterLeaveOrganizationUrl="/dashboard"
appearance={{
elements: {
rootBox: 'w-full',
card: 'w-full',
},
}}
/>
</div>
<OrganizationProfile
routing="path"
path={getI18nPath(
'/dashboard/organization-profile',
props.params.locale,
)}
afterLeaveOrganizationUrl="/onboarding/organization-selection"
appearance={{
elements: {
rootBox: 'w-full',
cardBox: 'w-full flex',
},
}}
/>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ const UserProfilePage = (props: { params: { locale: string } }) => {
description={t('title_bar_description')}
/>

<div className="flex justify-center">
<UserProfile
routing="path"
path={getI18nPath('/dashboard/user-profile', props.params.locale)}
appearance={{
elements: {
rootBox: 'w-full',
card: 'w-full',
},
}}
/>
</div>
<UserProfile
routing="path"
path={getI18nPath('/dashboard/user-profile', props.params.locale)}
appearance={{
elements: {
rootBox: 'w-full',
cardBox: 'w-full flex',
},
}}
/>
</>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/app/[locale]/(auth)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export default function AuthLayout(props: {
localization={clerkLocale}
signInUrl={signInUrl}
signUpUrl={signUpUrl}
afterSignInUrl={dashboardUrl}
afterSignUpUrl={dashboardUrl}
signInFallbackRedirectUrl={dashboardUrl}
signUpFallbackRedirectUrl={dashboardUrl}
>
{props.children}
</ClerkProvider>
Expand Down
2 changes: 2 additions & 0 deletions src/libs/Env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const Env = createEnv({
client: {
NEXT_PUBLIC_APP_URL: z.string().optional(),
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.string().min(1),
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1),
},
// You need to destructure all the keys manually
Expand All @@ -28,6 +29,7 @@ export const Env = createEnv({
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
NEXT_PUBLIC_CLERK_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY:
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
},
Expand Down
79 changes: 46 additions & 33 deletions src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { authMiddleware, redirectToSignIn } from '@clerk/nextjs';
import { type NextRequest, NextResponse } from 'next/server';
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
import {
type NextFetchEvent,
type NextRequest,
NextResponse,
} from 'next/server';
import createMiddleware from 'next-intl/middleware';

import { AllLocales, AppConfig } from './utils/AppConfig';
Expand All @@ -10,37 +14,46 @@ const intlMiddleware = createMiddleware({
defaultLocale: AppConfig.defaultLocale,
});

export default authMiddleware({
publicRoutes: (req: NextRequest) =>
!req.nextUrl.pathname.includes('/dashboard') &&
!req.nextUrl.pathname.includes('/onboarding'),

beforeAuth: (req) => {
// Execute next-intl middleware before Clerk's auth middleware
return intlMiddleware(req);
},

// eslint-disable-next-line consistent-return
afterAuth(auth, req) {
// Handle users who aren't authenticated
if (!auth.userId && !auth.isPublicRoute) {
return redirectToSignIn({ returnBackUrl: req.url });
}

if (
auth.userId &&
!auth.orgId &&
!req.nextUrl.pathname.endsWith('/onboarding/organization-selection')
) {
const organizationSelection = new URL(
'/onboarding/organization-selection',
req.url,
);

return NextResponse.redirect(organizationSelection);
}
},
});
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/:locale/dashboard(.*)',
'/onboarding(.*)',
'/:locale/onboarding(.*)',
]);

export default function middleware(
request: NextRequest,
event: NextFetchEvent,
) {
if (
request.nextUrl.pathname.includes('/sign-in') ||
request.nextUrl.pathname.includes('/sign-up') ||
isProtectedRoute(request)
) {
return clerkMiddleware((auth, req) => {
const authObj = auth();

if (isProtectedRoute(req)) authObj.protect();

if (
authObj.userId &&
!authObj.orgId &&
req.nextUrl.pathname.includes('/dashboard')
) {
const orgSelection = new URL(
'/onboarding/organization-selection',
req.url,
);

return NextResponse.redirect(orgSelection);
}

return intlMiddleware(req);
})(request, event);
}

return intlMiddleware(request);
}

export const config = {
matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
Expand Down
10 changes: 10 additions & 0 deletions src/types/Auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import type { EnumValues } from './Enum';

export const ORG_ROLE = {
ADMIN: 'org:admin',
MEMBER: 'org:member',
} as const;

export type OrgRole = EnumValues<typeof ORG_ROLE>;

export const ORG_PERMISSION = {
// Add Organization Permissions here
} as const;

export type OrgPermission = EnumValues<typeof ORG_PERMISSION>;
11 changes: 11 additions & 0 deletions src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */
import type { OrgPermission, OrgRole } from '@/types/Auth';

// Use type safe message keys with `next-intl`
type Messages = typeof import('../locales/en.json');
declare interface IntlMessages extends Messages {}

declare global {
interface ClerkAuthorization {
permission: OrgPermission;
role: OrgRole;
}
}

export {};

0 comments on commit a92cef0

Please sign in to comment.