diff --git a/.changeset/spotty-boxes-do.md b/.changeset/spotty-boxes-do.md new file mode 100644 index 00000000000..e8590d66965 --- /dev/null +++ b/.changeset/spotty-boxes-do.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': major +'@clerk/shared': patch +--- + +Change the default behavior of `afterSignOutUrl`, `afterSignIn` and `afterSignUp` props to be redirected to `/` instead of the Account Portal defined URL. diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 040e23a8c51..6a7ab91becc 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -915,13 +915,9 @@ export class Clerk implements ClerkInterface { buildURL({ base: displayConfig.signInUrl, hashPath: '/reset-password' }, { stringify: true }), ); - const navigateAfterSignIn = makeNavigate( - params.afterSignInUrl || params.redirectUrl || displayConfig.afterSignInUrl, - ); + const navigateAfterSignIn = makeNavigate(params.afterSignInUrl || params.redirectUrl || '/'); - const navigateAfterSignUp = makeNavigate( - params.afterSignUpUrl || params.redirectUrl || displayConfig.afterSignUpUrl, - ); + const navigateAfterSignUp = makeNavigate(params.afterSignUpUrl || params.redirectUrl || '/'); const navigateToContinueSignUp = makeNavigate( params.continueSignUpUrl || diff --git a/packages/clerk-js/src/ui.retheme/components/SignIn/SignInSocialButtons.tsx b/packages/clerk-js/src/ui.retheme/components/SignIn/SignInSocialButtons.tsx index 5b10d61fc16..2ba1b6aae35 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignIn/SignInSocialButtons.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignIn/SignInSocialButtons.tsx @@ -18,7 +18,7 @@ export const SignInSocialButtons = React.memo((props: SocialButtonsProps) => { const ctx = useSignInContext(); const signIn = useCoreSignIn(); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signInUrl); - const redirectUrlComplete = ctx.afterSignInUrl || displayConfig.afterSignInUrl; + const redirectUrlComplete = ctx.afterSignInUrl || '/'; return ( { const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signInUrl); - const redirectUrlComplete = ctx.afterSignInUrl || displayConfig.afterSignInUrl; + const redirectUrlComplete = ctx.afterSignInUrl || '/'; return signIn.authenticateWithRedirect({ strategy: 'saml', diff --git a/packages/clerk-js/src/ui.retheme/components/SignIn/__tests__/SignInStart.test.tsx b/packages/clerk-js/src/ui.retheme/components/SignIn/__tests__/SignInStart.test.tsx index f8be85f6774..41c7df4682c 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignIn/__tests__/SignInStart.test.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignIn/__tests__/SignInStart.test.tsx @@ -139,8 +139,8 @@ describe('SignInStart', () => { expect(fixtures.signIn.create).toHaveBeenCalled(); expect(fixtures.signIn.authenticateWithRedirect).toHaveBeenCalledWith({ strategy: 'saml', - redirectUrl: 'http://localhost/#/sso-callback', - redirectUrlComplete: 'https://dashboard.clerk.com', + redirectUrl: 'http://localhost/#/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F', + redirectUrlComplete: '/', }); }); }); diff --git a/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpSocialButtons.tsx b/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpSocialButtons.tsx index 921596b035f..4dd84f36039 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpSocialButtons.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpSocialButtons.tsx @@ -21,7 +21,7 @@ export const SignUpSocialButtons = React.memo((props: SignUpSocialButtonsProps) const ctx = useSignUpContext(); const signUp = useCoreSignUp(); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); - const redirectUrlComplete = ctx.afterSignUpUrl || displayConfig.afterSignUpUrl; + const redirectUrlComplete = ctx.afterSignUpUrl || '/'; const { continueSignUp = false, ...rest } = props; return ( diff --git a/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpStart.tsx b/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpStart.tsx index 33580d544cb..79fafd6967c 100644 --- a/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpStart.tsx +++ b/packages/clerk-js/src/ui.retheme/components/SignUp/SignUpStart.tsx @@ -211,7 +211,7 @@ function _SignUpStart(): JSX.Element { card.setError(undefined); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); - const redirectUrlComplete = ctx.afterSignUpUrl || displayConfig.afterSignUpUrl; + const redirectUrlComplete = ctx.afterSignUpUrl || '/'; return signUp .create(buildRequest(fieldsToSubmit)) diff --git a/packages/clerk-js/src/ui.retheme/contexts/ClerkUIComponentsContext.tsx b/packages/clerk-js/src/ui.retheme/contexts/ClerkUIComponentsContext.tsx index e3c6a73f9ee..5b0d548996e 100644 --- a/packages/clerk-js/src/ui.retheme/contexts/ClerkUIComponentsContext.tsx +++ b/packages/clerk-js/src/ui.retheme/contexts/ClerkUIComponentsContext.tsx @@ -69,8 +69,7 @@ export const useSignUpContext = (): SignUpContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const afterSignInUrl = clerk.buildUrlWithAuth( @@ -78,8 +77,7 @@ export const useSignUpContext = (): SignUpContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const navigateAfterSignUp = () => navigate(afterSignUpUrl); @@ -145,8 +143,7 @@ export const useSignInContext = (): SignInContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const afterSignInUrl = clerk.buildUrlWithAuth( @@ -154,8 +151,7 @@ export const useSignInContext = (): SignInContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const navigateAfterSignIn = () => navigate(afterSignInUrl); @@ -236,7 +232,7 @@ export const useUserButtonContext = () => { const afterMultiSessionSingleSignOutUrl = ctx.afterMultiSessionSingleSignOutUrl || displayConfig.afterSignOutOneUrl; const navigateAfterMultiSessionSingleSignOut = () => clerk.redirectWithAuth(afterMultiSessionSingleSignOutUrl); - const afterSignOutUrl = ctx.afterSignOutUrl || displayConfig.afterSignOutAllUrl; + const afterSignOutUrl = ctx.afterSignOutUrl || '/'; const navigateAfterSignOut = () => navigate(afterSignOutUrl); const afterSwitchSessionUrl = ctx.afterSwitchSessionUrl || displayConfig.afterSwitchSessionUrl; diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx index 5b10d61fc16..2ba1b6aae35 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx @@ -18,7 +18,7 @@ export const SignInSocialButtons = React.memo((props: SocialButtonsProps) => { const ctx = useSignInContext(); const signIn = useCoreSignIn(); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signInUrl); - const redirectUrlComplete = ctx.afterSignInUrl || displayConfig.afterSignInUrl; + const redirectUrlComplete = ctx.afterSignInUrl || '/'; return ( { const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signInUrl); - const redirectUrlComplete = ctx.afterSignInUrl || displayConfig.afterSignInUrl; + const redirectUrlComplete = ctx.afterSignInUrl || '/'; return signIn.authenticateWithRedirect({ strategy: 'saml', diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx index 719230e41d4..beda4ff0f81 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx @@ -138,8 +138,8 @@ describe('SignInStart', () => { expect(fixtures.signIn.create).toHaveBeenCalled(); expect(fixtures.signIn.authenticateWithRedirect).toHaveBeenCalledWith({ strategy: 'saml', - redirectUrl: 'http://localhost/#/sso-callback', - redirectUrlComplete: 'https://dashboard.clerk.com', + redirectUrl: 'http://localhost/#/sso-callback?redirect_url=http%3A%2F%2Flocalhost%2F', + redirectUrlComplete: '/', }); }); }); diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx index 921596b035f..4dd84f36039 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx @@ -21,7 +21,7 @@ export const SignUpSocialButtons = React.memo((props: SignUpSocialButtonsProps) const ctx = useSignUpContext(); const signUp = useCoreSignUp(); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); - const redirectUrlComplete = ctx.afterSignUpUrl || displayConfig.afterSignUpUrl; + const redirectUrlComplete = ctx.afterSignUpUrl || '/'; const { continueSignUp = false, ...rest } = props; return ( diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx index 33580d544cb..79fafd6967c 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx @@ -211,7 +211,7 @@ function _SignUpStart(): JSX.Element { card.setError(undefined); const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); - const redirectUrlComplete = ctx.afterSignUpUrl || displayConfig.afterSignUpUrl; + const redirectUrlComplete = ctx.afterSignUpUrl || '/'; return signUp .create(buildRequest(fieldsToSubmit)) diff --git a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx index e3c6a73f9ee..5b0d548996e 100644 --- a/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx +++ b/packages/clerk-js/src/ui/contexts/ClerkUIComponentsContext.tsx @@ -69,8 +69,7 @@ export const useSignUpContext = (): SignUpContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const afterSignInUrl = clerk.buildUrlWithAuth( @@ -78,8 +77,7 @@ export const useSignUpContext = (): SignUpContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const navigateAfterSignUp = () => navigate(afterSignUpUrl); @@ -145,8 +143,7 @@ export const useSignInContext = (): SignInContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const afterSignInUrl = clerk.buildUrlWithAuth( @@ -154,8 +151,7 @@ export const useSignInContext = (): SignInContextType => { queryParams, ctx, options, - displayConfig, - }), + }) || '/', ); const navigateAfterSignIn = () => navigate(afterSignInUrl); @@ -236,7 +232,7 @@ export const useUserButtonContext = () => { const afterMultiSessionSingleSignOutUrl = ctx.afterMultiSessionSingleSignOutUrl || displayConfig.afterSignOutOneUrl; const navigateAfterMultiSessionSingleSignOut = () => clerk.redirectWithAuth(afterMultiSessionSingleSignOutUrl); - const afterSignOutUrl = ctx.afterSignOutUrl || displayConfig.afterSignOutAllUrl; + const afterSignOutUrl = ctx.afterSignOutUrl || '/'; const navigateAfterSignOut = () => navigate(afterSignOutUrl); const afterSwitchSessionUrl = ctx.afterSwitchSessionUrl || displayConfig.afterSwitchSessionUrl; diff --git a/packages/clerk-js/src/utils/pagesToOffset.ts b/packages/clerk-js/src/utils/pagesToOffset.ts index 6f66cd8fb44..6834cd77a94 100644 --- a/packages/clerk-js/src/utils/pagesToOffset.ts +++ b/packages/clerk-js/src/utils/pagesToOffset.ts @@ -1,13 +1,6 @@ +import { getNonUndefinedValues } from '@clerk/shared'; import type { ClerkPaginationParams, ClerkPaginationRequest } from '@clerk/types'; -function getNonUndefinedValues(obj: Record): Record { - return Object.keys(obj).reduce((result, key) => { - if (obj[key] !== undefined) { - result[key] = obj[key]; - } - return result; - }, {} as Record); -} export function convertPageToOffset( pageParams: T, ): ClerkPaginationRequest { diff --git a/packages/remix/src/utils.ts b/packages/remix/src/utils.ts index d5f19dc27d8..dd880ce92c6 100644 --- a/packages/remix/src/utils.ts +++ b/packages/remix/src/utils.ts @@ -29,7 +29,7 @@ export function assertValidClerkState(val: any): asserts val is ClerkState | und * Utility function to get env variables across Node and Edge runtimes. * * @param name - * @returns + * @returns string */ export const getEnvVariable = (name: string, context: AppLoadContext | undefined): string => { // Node envs diff --git a/packages/shared/src/__tests__/underscore.test.ts b/packages/shared/src/__tests__/underscore.test.ts index 2a86c56a4cd..cc79525ab24 100644 --- a/packages/shared/src/__tests__/underscore.test.ts +++ b/packages/shared/src/__tests__/underscore.test.ts @@ -1,4 +1,12 @@ -import { deepCamelToSnake, deepSnakeToCamel, isIPV4Address, isTruthy, titleize, toSentence } from '../underscore'; +import { + deepCamelToSnake, + deepSnakeToCamel, + getNonUndefinedValues, + isIPV4Address, + isTruthy, + titleize, + toSentence, +} from '../underscore'; describe('toSentence', () => { it('returns a single item as-is', () => { @@ -204,3 +212,47 @@ describe(`isTruthy`, () => { expect(isTruthy(`foobar`)).toBe(false); }); }); + +describe('getNonUndefinedValues', () => { + it(`removes all the undefined values from the object`, () => { + const obj = { + a: 1, + b: undefined, + c: null, + }; + expect(getNonUndefinedValues(obj)).toStrictEqual({ + a: 1, + c: null, + }); + }); + + it(`returns the same object if no undefined value exists`, () => { + const obj = { + a: 1, + b: 'foo', + c: null, + }; + expect(getNonUndefinedValues(obj)).toStrictEqual(obj); + expect(getNonUndefinedValues({})).toStrictEqual({}); + }); + + it(`removes only the undefined values from the top level`, () => { + const obj = { + a: 1, + b: undefined, + c: null, + e: { + f: undefined, + g: 1, + }, + }; + expect(getNonUndefinedValues(obj)).toStrictEqual({ + a: 1, + c: null, + e: { + f: undefined, + g: 1, + }, + }); + }); +}); diff --git a/packages/shared/src/underscore.ts b/packages/shared/src/underscore.ts index 7558c17b91d..6339d8e355c 100644 --- a/packages/shared/src/underscore.ts +++ b/packages/shared/src/underscore.ts @@ -108,3 +108,12 @@ export function isTruthy(value: unknown): boolean { // Default to false return false; } + +export function getNonUndefinedValues(obj: T): Partial { + return Object.entries(obj).reduce((acc, [key, value]) => { + if (value !== undefined) { + acc[key as keyof T] = value; + } + return acc; + }, {} as Partial); +} diff --git a/playground/nextjs/pages/_app.tsx b/playground/nextjs/pages/_app.tsx index b63cb24b60a..117e2616c05 100644 --- a/playground/nextjs/pages/_app.tsx +++ b/playground/nextjs/pages/_app.tsx @@ -1,5 +1,5 @@ -import '../styles/globals.css'; import type { AppProps } from 'next/app'; +import '../styles/globals.css'; import { ClerkProvider, @@ -91,7 +91,7 @@ const AppBar = (props: AppBarProps) => { - +