From 9585a3826abd1bfc523a25e556b8c9af715bb26c Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 19 Dec 2024 18:31:16 -0500 Subject: [PATCH] wip --- packages/clerk-js/src/ui/common/redirects.ts | 12 +++++-- .../src/ui/components/SignIn/SignIn.tsx | 16 ++++++---- .../components/SignUp/SignUpEmailLinkCard.tsx | 9 +++--- .../components/SignUp/SignUpSocialButtons.tsx | 5 +-- .../src/ui/components/SignUp/SignUpStart.tsx | 6 ++-- .../src/ui/contexts/components/SignIn.ts | 31 ++++++++++++++++--- .../src/ui/contexts/components/SignUp.ts | 27 ++++++++++++++++ packages/clerk-js/src/ui/types.ts | 2 ++ 8 files changed, 84 insertions(+), 24 deletions(-) diff --git a/packages/clerk-js/src/ui/common/redirects.ts b/packages/clerk-js/src/ui/common/redirects.ts index 347b45bf9a..f8bfaf6a36 100644 --- a/packages/clerk-js/src/ui/common/redirects.ts +++ b/packages/clerk-js/src/ui/common/redirects.ts @@ -1,8 +1,8 @@ import { buildURL } from '../../utils/url'; import type { SignInContextType, SignUpContextType, UserProfileContextType } from './../contexts'; -const SSO_CALLBACK_PATH_ROUTE = '/sso-callback'; -const MAGIC_LINK_VERIFY_PATH_ROUTE = '/verify'; +export const SSO_CALLBACK_PATH_ROUTE = '/sso-callback'; +export const MAGIC_LINK_VERIFY_PATH_ROUTE = '/verify'; export function buildEmailLinkRedirectUrl( ctx: SignInContextType | SignUpContextType | UserProfileContextType, @@ -43,7 +43,13 @@ type BuildRedirectUrlParams = { endpoint: string; }; -const buildRedirectUrl = ({ routing, authQueryString, baseUrl, path, endpoint }: BuildRedirectUrlParams): string => { +export const buildRedirectUrl = ({ + routing, + authQueryString, + baseUrl, + path, + endpoint, +}: BuildRedirectUrlParams): string => { // If a routing strategy is not provided, default to hash routing // All routing strategies know how to convert a hash-based url to their own format // Example: navigating from a hash-based to a path-based component, diff --git a/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx b/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx index ea783fc013..de8722f918 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx @@ -2,7 +2,9 @@ import { useClerk } from '@clerk/shared/react'; import type { SignInModalProps, SignInProps } from '@clerk/types'; import React from 'react'; +import { normalizeRoutingOptions } from '../../../utils/normalizeRoutingOptions'; import { SignInEmailLinkFlowComplete, SignUpEmailLinkFlowComplete } from '../../common/EmailLinkCompleteFlowCard'; +import type { SignUpContextType } from '../../contexts'; import { SignInContext, SignUpContext, @@ -145,14 +147,16 @@ function SignInRoutes(): JSX.Element { function SignInRoot() { const signInContext = useSignInContext(); + const normalizedProps = { + componentName: 'SignUp', + ...signInContext.__experimental?.combinedProps, + emailLinkRedirectUrl: signInContext.emailLinkRedirectUrl, + ssoCallbackUrl: signInContext.ssoCallbackUrl, + ...normalizeRoutingOptions({ routing: signInContext?.routing, path: signInContext?.path }), + } as SignUpContextType; return ( - + ); diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx index a5b701e4c9..b1a9aec6c0 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailLinkCard.tsx @@ -3,8 +3,7 @@ import type { SignUpResource } from '@clerk/types'; import React from 'react'; import { EmailLinkStatusCard } from '../../common'; -import { buildEmailLinkRedirectUrl } from '../../common/redirects'; -import { useCoreSignUp, useEnvironment, useSignUpContext } from '../../contexts'; +import { useCoreSignUp, useSignUpContext } from '../../contexts'; import { Flow, localizationKeys, useLocalizations } from '../../customizables'; import { VerificationLinkCard } from '../../elements'; import { useCardState } from '../../elements/contexts'; @@ -19,7 +18,6 @@ export const SignUpEmailLinkCard = () => { const signUpContext = useSignUpContext(); const { afterSignUpUrl } = signUpContext; const card = useCardState(); - const { displayConfig } = useEnvironment(); const { navigate } = useRouter(); const { setActive } = useClerk(); const [showVerifyModal, setShowVerifyModal] = React.useState(false); @@ -36,7 +34,9 @@ export const SignUpEmailLinkCard = () => { }; const startEmailLinkVerification = () => { - return startEmailLinkFlow({ redirectUrl: buildEmailLinkRedirectUrl(signUpContext, displayConfig.signUpUrl) }) + return startEmailLinkFlow({ + redirectUrl: signUpContext.emailLinkRedirectUrl, + }) .then(res => handleVerificationResult(res)) .catch(err => { handleError(err, [], card.setError); @@ -52,6 +52,7 @@ export const SignUpEmailLinkCard = () => { } else { await completeSignUpFlow({ signUp: su, + continuePath: '../continue', verifyEmailPath: '../verify-email-address', verifyPhonePath: '../verify-phone-number', handleComplete: () => setActive({ session: su.createdSessionId, redirectUrl: afterSignUpUrl }), diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx index 9ae045a8a6..c662d07257 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpSocialButtons.tsx @@ -2,9 +2,7 @@ import { useClerk } from '@clerk/shared/react'; import type { OAuthStrategy } from '@clerk/types'; import React from 'react'; -import { buildSSOCallbackURL } from '../../common/redirects'; import { useCoreSignUp, useSignUpContext } from '../../contexts'; -import { useEnvironment } from '../../contexts/EnvironmentContext'; import { useCardState } from '../../elements'; import type { SocialButtonsProps } from '../../elements/SocialButtons'; import { SocialButtons } from '../../elements/SocialButtons'; @@ -17,10 +15,9 @@ export const SignUpSocialButtons = React.memo((props: SignUpSocialButtonsProps) const clerk = useClerk(); const { navigate } = useRouter(); const card = useCardState(); - const { displayConfig } = useEnvironment(); const ctx = useSignUpContext(); const signUp = useCoreSignUp(); - const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); + const redirectUrl = ctx.ssoCallbackUrl; const redirectUrlComplete = ctx.afterSignUpUrl || '/'; const { continueSignUp = false, ...rest } = props; diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx index 3f000a1fe5..879c48034e 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { ERROR_CODES, SIGN_UP_MODES } from '../../../core/constants'; import { getClerkQueryParam, removeClerkQueryParam } from '../../../utils/getClerkQueryParam'; -import { buildSSOCallbackURL, withRedirectToAfterSignUp } from '../../common'; +import { withRedirectToAfterSignUp } from '../../common'; import { SignInContext, useCoreSignUp, useEnvironment, useOptions, useSignUpContext } from '../../contexts'; import { descriptors, Flex, Flow, localizationKeys, useAppearance, useLocalizations } from '../../customizables'; import { @@ -34,7 +34,7 @@ function _SignUpStart(): JSX.Element { const status = useLoadingStatus(); const signUp = useCoreSignUp(); const { showOptionalFields } = useAppearance().parsedLayout; - const { userSettings, displayConfig } = useEnvironment(); + const { userSettings } = useEnvironment(); const { navigate } = useRouter(); const { attributes } = userSettings; const { setActive } = useClerk(); @@ -234,7 +234,7 @@ function _SignUpStart(): JSX.Element { card.setLoading(); card.setError(undefined); - const redirectUrl = buildSSOCallbackURL(ctx, displayConfig.signUpUrl); + const redirectUrl = ctx.ssoCallbackUrl; const redirectUrlComplete = ctx.afterSignUpUrl || '/'; return signUp diff --git a/packages/clerk-js/src/ui/contexts/components/SignIn.ts b/packages/clerk-js/src/ui/contexts/components/SignIn.ts index e089e0f1b9..7af4515690 100644 --- a/packages/clerk-js/src/ui/contexts/components/SignIn.ts +++ b/packages/clerk-js/src/ui/contexts/components/SignIn.ts @@ -4,6 +4,7 @@ import { createContext, useContext, useMemo } from 'react'; import { SIGN_IN_INITIAL_VALUE_KEYS } from '../../../core/constants'; import { buildURL } from '../../../utils'; import { RedirectUrls } from '../../../utils/redirectUrls'; +import { buildRedirectUrl, MAGIC_LINK_VERIFY_PATH_ROUTE, SSO_CALLBACK_PATH_ROUTE } from '../../common/redirects'; import { useEnvironment, useOptions } from '../../contexts'; import type { ParsedQueryString } from '../../router'; import { useRouter } from '../../router'; @@ -21,6 +22,8 @@ export type SignInContextType = SignInCtx & { afterSignInUrl: string; transferable: boolean; waitlistUrl: string; + emailLinkRedirectUrl: string; + ssoCallbackUrl: string; }; export const SignInContext = createContext(null); @@ -32,14 +35,14 @@ export const useSignInContext = (): SignInContextType => { const { queryParams, queryString } = useRouter(); const options = useOptions(); const clerk = useClerk(); + const isCombinedFlow = options.experimental?.combinedFlow; if (context === null || context.componentName !== 'SignIn') { throw new Error(`Clerk: useSignInContext called outside of the mounted SignIn component.`); } const { componentName, mode, ..._ctx } = context; - const ctx = _ctx.__experimental?.combinedProps || _ctx; - + const ctx = _ctx.__experimental?.combinedProps ? { ..._ctx, ..._ctx.__experimental?.combinedProps } : _ctx; const initialValuesFromQueryParams = useMemo( () => getInitialValuesFromQueryParams(queryString, SIGN_IN_INITIAL_VALUE_KEYS), [], @@ -65,15 +68,33 @@ export const useSignInContext = (): SignInContextType => { // SignIn's own options won't have a `signInUrl` property, so we have to get the value // from the `path` prop instead, when the routing is set to 'path'. let signInUrl = (ctx.routing === 'path' && ctx.path) || options.signInUrl || displayConfig.signInUrl; - let signUpUrl = ctx.signUpUrl || options.signUpUrl || displayConfig.signUpUrl; + let signUpUrl = isCombinedFlow + ? (ctx.routing === 'path' && ctx.path) || options.signUpUrl || displayConfig.signUpUrl + : ctx.signUpUrl || options.signUpUrl || displayConfig.signUpUrl; let waitlistUrl = ctx.waitlistUrl || options.waitlistUrl || displayConfig.waitlistUrl; const preservedParams = redirectUrls.getPreservedSearchParams(); signInUrl = buildURL({ base: signInUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); signUpUrl = buildURL({ base: signUpUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); waitlistUrl = buildURL({ base: waitlistUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); + const emailLinkRedirectUrl = buildRedirectUrl({ + routing: ctx.routing, + baseUrl: signUpUrl, + authQueryString: '', + path: ctx.path, + endpoint: options.experimental?.combinedFlow + ? '/create' + MAGIC_LINK_VERIFY_PATH_ROUTE + : MAGIC_LINK_VERIFY_PATH_ROUTE, + }); + const ssoCallbackUrl = buildRedirectUrl({ + routing: ctx.routing, + baseUrl: signUpUrl, + authQueryString: '', + path: ctx.path, + endpoint: options.experimental?.combinedFlow ? '/create' + SSO_CALLBACK_PATH_ROUTE : SSO_CALLBACK_PATH_ROUTE, + }); - if (options.experimental?.combinedFlow) { + if (isCombinedFlow) { signUpUrl = buildURL( { base: signInUrl, hashPath: '/create', hashSearchParams: [queryParams, preservedParams] }, { stringify: true }, @@ -91,6 +112,8 @@ export const useSignInContext = (): SignInContextType => { waitlistUrl, afterSignInUrl, afterSignUpUrl, + emailLinkRedirectUrl, + ssoCallbackUrl, navigateAfterSignIn, signUpContinueUrl, queryParams, diff --git a/packages/clerk-js/src/ui/contexts/components/SignUp.ts b/packages/clerk-js/src/ui/contexts/components/SignUp.ts index 643525c4ef..3fad601803 100644 --- a/packages/clerk-js/src/ui/contexts/components/SignUp.ts +++ b/packages/clerk-js/src/ui/contexts/components/SignUp.ts @@ -4,6 +4,7 @@ import { createContext, useContext, useMemo } from 'react'; import { SIGN_UP_INITIAL_VALUE_KEYS } from '../../../core/constants'; import { buildURL } from '../../../utils'; import { RedirectUrls } from '../../../utils/redirectUrls'; +import { buildRedirectUrl, MAGIC_LINK_VERIFY_PATH_ROUTE, SSO_CALLBACK_PATH_ROUTE } from '../../common/redirects'; import { useEnvironment, useOptions } from '../../contexts'; import type { ParsedQueryString } from '../../router'; import { useRouter } from '../../router'; @@ -20,6 +21,8 @@ export type SignUpContextType = SignUpCtx & { afterSignUpUrl: string; afterSignInUrl: string; waitlistUrl: string; + emailLinkRedirectUrl: string; + ssoCallbackUrl: string; }; export const SignUpContext = createContext(null); @@ -63,6 +66,7 @@ export const useSignUpContext = (): SignUpContextType => { // SignUp's own options won't have a `signUpUrl` property, so we have to get the value // from the `path` prop instead, when the routing is set to 'path'. let signUpUrl = (ctx.routing === 'path' && ctx.path) || options.signUpUrl || displayConfig.signUpUrl; + console.log({ signUpUrlBeforeBuildUrlInSignUp: signUpUrl }); let signInUrl = ctx.signInUrl || options.signInUrl || displayConfig.signInUrl; let waitlistUrl = ctx.waitlistUrl || options.waitlistUrl || displayConfig.waitlistUrl; @@ -71,6 +75,27 @@ export const useSignUpContext = (): SignUpContextType => { signUpUrl = buildURL({ base: signUpUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); waitlistUrl = buildURL({ base: waitlistUrl, hashSearchParams: [queryParams, preservedParams] }, { stringify: true }); + const emailLinkRedirectUrl = + ctx.emailLinkRedirectUrl ?? + buildRedirectUrl({ + routing: ctx.routing, + baseUrl: signUpUrl, + authQueryString: '', + path: ctx.path, + endpoint: options.experimental?.combinedFlow + ? '/create' + MAGIC_LINK_VERIFY_PATH_ROUTE + : MAGIC_LINK_VERIFY_PATH_ROUTE, + }); + const ssoCallbackUrl = + ctx.ssoCallbackUrl ?? + buildRedirectUrl({ + routing: ctx.routing, + baseUrl: signUpUrl, + authQueryString: '', + path: ctx.path, + endpoint: options.experimental?.combinedFlow ? '/create' + SSO_CALLBACK_PATH_ROUTE : SSO_CALLBACK_PATH_ROUTE, + }); + // TODO: Avoid building this url again to remove duplicate code. Get it from window.Clerk instead. const secondFactorUrl = buildURL({ base: signInUrl, hashPath: '/factor-two' }, { stringify: true }); @@ -83,6 +108,8 @@ export const useSignUpContext = (): SignUpContextType => { secondFactorUrl, afterSignUpUrl, afterSignInUrl, + emailLinkRedirectUrl, + ssoCallbackUrl, navigateAfterSignUp, queryParams, initialValues: { ...ctx.initialValues, ...initialValuesFromQueryParams }, diff --git a/packages/clerk-js/src/ui/types.ts b/packages/clerk-js/src/ui/types.ts index d9af51adce..e90ebfff24 100644 --- a/packages/clerk-js/src/ui/types.ts +++ b/packages/clerk-js/src/ui/types.ts @@ -58,6 +58,8 @@ export type UserProfileCtx = UserProfileProps & { export type SignUpCtx = SignUpProps & { componentName: 'SignUp'; mode?: ComponentMode; + emailLinkRedirectUrl?: string; + ssoCallbackUrl?: string; }; export type UserButtonCtx = UserButtonProps & {