Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
alexcarpenter committed Dec 19, 2024
1 parent c6837d1 commit 9585a38
Showing 8 changed files with 84 additions and 24 deletions.
12 changes: 9 additions & 3 deletions packages/clerk-js/src/ui/common/redirects.ts
Original file line number Diff line number Diff line change
@@ -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,
16 changes: 10 additions & 6 deletions packages/clerk-js/src/ui/components/SignIn/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<SignUpContext.Provider
value={{
componentName: 'SignUp',
...signInContext.__experimental?.combinedProps,
}}
>
<SignUpContext.Provider value={normalizedProps}>
<SignInRoutes />
</SignUpContext.Provider>
);
Original file line number Diff line number Diff line change
@@ -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 }),
Original file line number Diff line number Diff line change
@@ -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;

6 changes: 3 additions & 3 deletions packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx
Original file line number Diff line number Diff line change
@@ -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
31 changes: 27 additions & 4 deletions packages/clerk-js/src/ui/contexts/components/SignIn.ts
Original file line number Diff line number Diff line change
@@ -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<SignInCtx | null>(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,
27 changes: 27 additions & 0 deletions packages/clerk-js/src/ui/contexts/components/SignUp.ts
Original file line number Diff line number Diff line change
@@ -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<SignUpCtx | null>(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 },
2 changes: 2 additions & 0 deletions packages/clerk-js/src/ui/types.ts
Original file line number Diff line number Diff line change
@@ -58,6 +58,8 @@ export type UserProfileCtx = UserProfileProps & {
export type SignUpCtx = SignUpProps & {
componentName: 'SignUp';
mode?: ComponentMode;
emailLinkRedirectUrl?: string;
ssoCallbackUrl?: string;
};

export type UserButtonCtx = UserButtonProps & {

0 comments on commit 9585a38

Please sign in to comment.