diff --git a/.changeset/mean-pumas-cut.md b/.changeset/mean-pumas-cut.md new file mode 100644 index 00000000000..a5936ab2a2e --- /dev/null +++ b/.changeset/mean-pumas-cut.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': patch +'@clerk/types': patch +--- + +Fix incorrect redirect when completing session tasks within `SignIn` and `SignUp` components diff --git a/integration/tests/session-tasks-sign-in.test.ts b/integration/tests/session-tasks-sign-in.test.ts index f91a3ec3f85..503d11dcb4b 100644 --- a/integration/tests/session-tasks-sign-in.test.ts +++ b/integration/tests/session-tasks-sign-in.test.ts @@ -56,7 +56,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })( await u.po.expect.toHaveResolvedTask(); // Navigates to after sign-in - await u.page.waitForAppUrl('/'); + await u.page.waitForAppUrl('/page-protected'); }); test('with sso, navigate to task on after sign-in', async ({ page, context }) => { diff --git a/integration/tests/session-tasks-sign-up.test.ts b/integration/tests/session-tasks-sign-up.test.ts index ca262f281e5..0a7c24c4eea 100644 --- a/integration/tests/session-tasks-sign-up.test.ts +++ b/integration/tests/session-tasks-sign-up.test.ts @@ -73,7 +73,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })( await u.po.expect.toHaveResolvedTask(); // Navigates to after sign-up - await u.page.waitForAppUrl('/'); + await u.page.waitForAppUrl('/page-protected'); }); test('with sso, navigate to task on after sign-up', async ({ page, context }) => { diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index ac78f078b6b..914fdcbdfb5 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -75,6 +75,7 @@ import type { SignUpRedirectOptions, SignUpResource, TaskChooseOrganizationProps, + TasksRedirectOptions, UnsubscribeCallback, UserButtonProps, UserProfileProps, @@ -1595,7 +1596,7 @@ export class Clerk implements ClerkInterface { return this.buildUrlWithAuth(this.environment.displayConfig.organizationProfileUrl); } - public buildTasksUrl(): string { + public buildTasksUrl(options?: TasksRedirectOptions): string { const currentTask = this.session?.currentTask; if (!currentTask) { return ''; @@ -1608,7 +1609,7 @@ export class Clerk implements ClerkInterface { return buildURL( { - base: this.buildSignInUrl(), + base: this.buildSignInUrl(options), hashPath: getTaskEndpoint(currentTask), }, { @@ -1707,9 +1708,9 @@ export class Clerk implements ClerkInterface { return; }; - public redirectToTasks = async (): Promise => { + public redirectToTasks = async (options?: TasksRedirectOptions): Promise => { if (inBrowser()) { - return this.navigate(this.buildTasksUrl()); + return this.navigate(this.buildTasksUrl(options)); } return; }; @@ -2044,7 +2045,9 @@ export class Clerk implements ClerkInterface { } if (this.session?.currentTask) { - await this.redirectToTasks(); + await this.redirectToTasks({ + redirectUrl: this.buildAfterSignInUrl(), + }); return; } diff --git a/packages/clerk-js/src/ui/components/SessionTasks/index.tsx b/packages/clerk-js/src/ui/components/SessionTasks/index.tsx index 3baba7afd2e..95d7ae017eb 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/index.tsx +++ b/packages/clerk-js/src/ui/components/SessionTasks/index.tsx @@ -1,14 +1,13 @@ import { useClerk } from '@clerk/shared/react'; import { eventComponentMounted } from '@clerk/shared/telemetry'; import type { SessionResource } from '@clerk/types'; -import { useContext, useEffect, useRef } from 'react'; +import { useEffect, useRef } from 'react'; import { Card } from '@/ui/elements/Card'; import { withCardStateProvider } from '@/ui/elements/contexts'; import { LoadingCardContainer } from '@/ui/elements/LoadingCard'; import { INTERNAL_SESSION_TASK_ROUTE_BY_KEY } from '../../../core/sessionTasks'; -import { SignInContext, SignUpContext } from '../../../ui/contexts'; import { SessionTasksContext, TaskChooseOrganizationContext, @@ -62,19 +61,18 @@ function SessionTasksRoutes(): JSX.Element { ); } +type SessionTasksProps = { + redirectUrlComplete: string; +}; + /** * @internal */ -export const SessionTasks = withCardStateProvider(() => { +export const SessionTasks = withCardStateProvider(({ redirectUrlComplete }: SessionTasksProps) => { const clerk = useClerk(); const { navigate } = useRouter(); - const signInContext = useContext(SignInContext); - const signUpContext = useContext(SignUpContext); const currentTaskContainer = useRef(null); - const redirectUrlComplete = - signInContext?.afterSignInUrl ?? signUpContext?.afterSignUpUrl ?? clerk?.buildAfterSignInUrl(); - // If there are no pending tasks, navigate away from the tasks flow. // This handles cases where a user with an active session returns to the tasks URL, // for example by using browser back navigation. Since there are no pending tasks, diff --git a/packages/clerk-js/src/ui/components/SignIn/index.tsx b/packages/clerk-js/src/ui/components/SignIn/index.tsx index cf451cf5ab3..29ec373b367 100644 --- a/packages/clerk-js/src/ui/components/SignIn/index.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/index.tsx @@ -136,7 +136,7 @@ function SignInRoutes(): JSX.Element { - + @@ -144,7 +144,7 @@ function SignInRoutes(): JSX.Element { )} - + diff --git a/packages/clerk-js/src/ui/components/SignUp/index.tsx b/packages/clerk-js/src/ui/components/SignUp/index.tsx index 6cfe5963605..a46993739fd 100644 --- a/packages/clerk-js/src/ui/components/SignUp/index.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/index.tsx @@ -80,7 +80,7 @@ function SignUpRoutes(): JSX.Element { - + diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index 6ac89e1becb..8e954c8f2a5 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -6,7 +6,7 @@ import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext'; import { useSessionContext } from '../contexts/SessionContext'; import { useAuth } from '../hooks'; import { useAssertWrappedByClerkProvider } from '../hooks/useAssertWrappedByClerkProvider'; -import type { RedirectToSignInProps, RedirectToSignUpProps, WithClerkProp } from '../types'; +import type { RedirectToSignInProps, RedirectToSignUpProps, RedirectToTasksProps, WithClerkProp } from '../types'; import { withClerk } from './withClerk'; export const SignedIn = ({ children, treatPendingAsSignedOut }: React.PropsWithChildren) => { @@ -166,9 +166,9 @@ export const RedirectToSignUp = withClerk(({ clerk, ...props }: WithClerkProp { +export const RedirectToTasks = withClerk(({ clerk, ...props }: WithClerkProp) => { React.useEffect(() => { - void clerk.redirectToTasks(); + void clerk.redirectToTasks(props); }, []); return null; diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 22f70b3aaa3..1e94bc0a6c9 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -45,6 +45,7 @@ import type { SignUpResource, State, TaskChooseOrganizationProps, + TasksRedirectOptions, UnsubscribeCallback, UserButtonProps, UserProfileProps, @@ -1276,8 +1277,8 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - redirectToTasks = async () => { - const callback = () => this.clerkjs?.redirectToTasks(); + redirectToTasks = async (opts?: TasksRedirectOptions) => { + const callback = () => this.clerkjs?.redirectToTasks(opts); if (this.clerkjs && this.loaded) { return callback(); } else { diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index b24a28a4df0..1865241e02c 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -9,6 +9,7 @@ import type { RedirectUrlProp, SignInRedirectOptions, SignUpRedirectOptions, + TasksRedirectOptions, Without, } from '@clerk/types'; import type React from 'react'; @@ -116,6 +117,7 @@ export type SignInWithMetamaskButtonProps = { export type RedirectToSignInProps = SignInRedirectOptions; export type RedirectToSignUpProps = SignUpRedirectOptions; +export type RedirectToTasksProps = TasksRedirectOptions; type PageProps = | { diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index a9105e5b64e..f53dbddc0bb 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -769,8 +769,10 @@ export interface Clerk { /** * Redirects to the configured URL where tasks are mounted. + * + * @param opts A {@link RedirectOptions} object */ - redirectToTasks(): Promise; + redirectToTasks(opts?: TasksRedirectOptions): Promise; /** * Completes a Google One Tap redirection flow started by @@ -1162,6 +1164,8 @@ export type SignUpInitialValues = { username?: string; }; +export type TasksRedirectOptions = RedirectOptions & RedirectUrlProp; + export type SignInRedirectOptions = RedirectOptions & RedirectUrlProp & { /** diff --git a/packages/vue/src/components/controlComponents.ts b/packages/vue/src/components/controlComponents.ts index cb787b1d8cf..195dd0f1590 100644 --- a/packages/vue/src/components/controlComponents.ts +++ b/packages/vue/src/components/controlComponents.ts @@ -60,9 +60,9 @@ export const RedirectToSignUp = defineComponent((props: RedirectOptions) => { return () => null; }); -export const RedirectToTasks = defineComponent(() => { +export const RedirectToTasks = defineComponent((props: RedirectOptions) => { useClerkLoaded(clerk => { - void clerk.redirectToTasks(); + void clerk.redirectToTasks(props); }); return () => null;