Skip to content

Commit 2de7ac4

Browse files
fix(clerk-js): Redirect to current page within modal with no redirect url (#4768)
1 parent 5286884 commit 2de7ac4

File tree

7 files changed

+35
-3
lines changed

7 files changed

+35
-3
lines changed

.changeset/young-swans-sin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': minor
3+
---
4+
5+
Redirect to the current page when within modal mode and no redirect URL is provided.

packages/clerk-js/src/ui/components/SignIn/SignIn.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ export const SignInModal = (props: SignInModalProps): JSX.Element => {
176176
componentName: 'SignIn',
177177
...signInProps,
178178
routing: 'virtual',
179+
mode: 'modal',
179180
}}
180181
>
181182
{/*TODO: Used by InvisibleRootBox, can we simplify? */}

packages/clerk-js/src/ui/components/SignUp/SignUp.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const SignUpModal = (props: SignUpModalProps): JSX.Element => {
103103
componentName: 'SignUp',
104104
...signUpProps,
105105
routing: 'virtual',
106+
mode: 'modal',
106107
}}
107108
>
108109
{/*TODO: Used by InvisibleRootBox, can we simplify? */}

packages/clerk-js/src/ui/contexts/components/SignIn.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const useSignInContext = (): SignInContextType => {
3737
throw new Error(`Clerk: useSignInContext called outside of the mounted SignIn component.`);
3838
}
3939

40-
const { componentName, ..._ctx } = context;
40+
const { componentName, mode, ..._ctx } = context;
4141
const ctx = _ctx.__experimental?.combinedProps || _ctx;
4242

4343
const initialValuesFromQueryParams = useMemo(
@@ -53,6 +53,7 @@ export const useSignInContext = (): SignInContextType => {
5353
signInForceRedirectUrl: ctx.forceRedirectUrl,
5454
},
5555
queryParams,
56+
mode,
5657
);
5758

5859
const afterSignInUrl = clerk.buildUrlWithAuth(redirectUrls.getAfterSignInUrl());

packages/clerk-js/src/ui/contexts/components/SignUp.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const useSignUpContext = (): SignUpContextType => {
4141
throw new Error('Clerk: useSignUpContext called outside of the mounted SignUp component.');
4242
}
4343

44-
const { componentName, ...ctx } = context;
44+
const { componentName, mode, ...ctx } = context;
4545

4646
const redirectUrls = new RedirectUrls(
4747
options,
@@ -51,6 +51,7 @@ export const useSignUpContext = (): SignUpContextType => {
5151
signUpForceRedirectUrl: ctx.forceRedirectUrl,
5252
},
5353
queryParams,
54+
mode,
5455
);
5556

5657
const afterSignUpUrl = clerk.buildUrlWithAuth(redirectUrls.getAfterSignUpUrl());

packages/clerk-js/src/utils/__tests__/redirectUrls.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,21 @@ describe('redirectUrls', () => {
244244
expect(redirectUrls.getAfterSignInUrl()).toBe(`${mockWindowLocation.href}search-param-redirect-url`);
245245
expect(redirectUrls.getAfterSignUpUrl()).toBe(`${mockWindowLocation.href}search-param-redirect-url`);
246246
});
247+
248+
it('returns to `/` when no redirect_url is found', () => {
249+
const redirectUrls = new RedirectUrls({}, {}, {});
250+
expect(redirectUrls.getAfterSignInUrl()).toBe('/');
251+
expect(redirectUrls.getAfterSignUpUrl()).toBe('/');
252+
});
253+
254+
it('returns current window location when in modal mode and no redirect_url is found', () => {
255+
const aboutPageUrl = 'https://www.clerk.com/about';
256+
mockWindowLocation = new URL(aboutPageUrl) as any as Window['location'];
257+
Object.defineProperty(global.window, 'location', { value: mockWindowLocation });
258+
const redirectUrls = new RedirectUrls({}, {}, {}, 'modal');
259+
expect(redirectUrls.getAfterSignInUrl()).toBe(aboutPageUrl);
260+
expect(redirectUrls.getAfterSignUpUrl()).toBe(aboutPageUrl);
261+
});
247262
});
248263

249264
describe('search params', () => {

packages/clerk-js/src/utils/redirectUrls.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import type { ClerkOptions, RedirectOptions } from '@clerk/types';
55
import { assertNoLegacyProp, warnForNewPropShadowingLegacyProp } from './assertNoLegacyProp';
66
import { isAllowedRedirect, relativeToAbsoluteUrl } from './url';
77

8+
type ComponentMode = 'modal' | 'mounted';
9+
810
export class RedirectUrls {
911
private static keys: (keyof RedirectOptions)[] = [
1012
'signInForceRedirectUrl',
@@ -22,12 +24,14 @@ export class RedirectUrls {
2224
private readonly fromOptions: RedirectOptions;
2325
private readonly fromProps: RedirectOptions;
2426
private readonly fromSearchParams: RedirectOptions & { redirectUrl?: string | null };
27+
private readonly mode?: ComponentMode;
2528

26-
constructor(options: ClerkOptions, props: RedirectOptions = {}, searchParams: any = {}) {
29+
constructor(options: ClerkOptions, props: RedirectOptions = {}, searchParams: any = {}, mode?: ComponentMode) {
2730
this.options = options;
2831
this.fromOptions = this.#parse(options || {});
2932
this.fromProps = this.#parse(props || {});
3033
this.fromSearchParams = this.#parseSearchParams(searchParams || {});
34+
this.mode = mode;
3135
}
3236

3337
getAfterSignInUrl() {
@@ -136,6 +140,10 @@ export class RedirectUrls {
136140
warnForNewPropShadowingLegacyProp(newKeyInUse, result, legacyPropKey, legacyValue);
137141
result ||= legacyValue;
138142

143+
if (!result && this.mode === 'modal') {
144+
return window.location.href;
145+
}
146+
139147
return result || '/';
140148
}
141149

0 commit comments

Comments
 (0)