diff --git a/packages/elements/src/internals/constants/index.ts b/packages/elements/src/internals/constants/index.ts index 135bdfd35aa..1cf45290c01 100644 --- a/packages/elements/src/internals/constants/index.ts +++ b/packages/elements/src/internals/constants/index.ts @@ -48,6 +48,7 @@ export const ERROR_CODES = { FORM_PASSWORD_INCORRECT: 'form_password_incorrect', INVALID_STRATEGY_FOR_USER: 'strategy_for_user_invalid', NOT_ALLOWED_TO_SIGN_UP: 'not_allowed_to_sign_up', + SIGN_UP_RESTRICTED_WAITLIST: 'sign_up_restricted_waitlist', OAUTH_ACCESS_DENIED: 'oauth_access_denied', OAUTH_EMAIL_DOMAIN_RESERVED_BY_SAML: 'oauth_email_domain_reserved_by_saml', NOT_ALLOWED_ACCESS: 'not_allowed_access', diff --git a/packages/elements/src/internals/machines/form/form.machine.ts b/packages/elements/src/internals/machines/form/form.machine.ts index 71c1cfb5bbc..ccdfcb3a875 100644 --- a/packages/elements/src/internals/machines/form/form.machine.ts +++ b/packages/elements/src/internals/machines/form/form.machine.ts @@ -101,10 +101,14 @@ export const FormMachine = setup({ if (isKnownError(event.error)) { const fields: Record = {}; const globalErrors: ClerkElementsError[] = []; - const errors = isClerkAPIResponseError(event.error) ? event.error?.errors : [event.error]; + const candidate = isClerkAPIResponseError(event.error) + ? event.error?.errors || event.error + : event?.error || []; + + const errors = Array.isArray(candidate) ? candidate : [candidate]; for (const error of errors) { - const name = isClerkAPIError(error) ? snakeToCamel(error.meta?.paramName) : null; + const name = isClerkAPIError(error) ? snakeToCamel(error?.meta?.paramName) : null; if (!name || isMetamaskError(error)) { globalErrors.push(ClerkElementsError.fromAPIError(error)); @@ -140,6 +144,7 @@ export const FormMachine = setup({ } }), }, + 'ERRORS.CLEAR': { actions: assign({ errors: () => [], diff --git a/packages/elements/src/internals/machines/sign-in/router.machine.ts b/packages/elements/src/internals/machines/sign-in/router.machine.ts index d012894beb1..14bca8a1365 100644 --- a/packages/elements/src/internals/machines/sign-in/router.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/router.machine.ts @@ -33,14 +33,14 @@ export type TSignInRouterMachine = typeof SignInRouterMachine; const isCurrentPath = (path: `/${string}`) => - ({ context }: { context: SignInRouterContext }, _params?: NonReducibleUnknown) => { - return context.router?.match(path) ?? false; - }; + ({ context }: { context: SignInRouterContext }, _params?: NonReducibleUnknown) => { + return context.router?.match(path) ?? false; + }; const needsStatus = (status: SignInStatus) => - ({ context, event }: { context: SignInRouterContext; event?: SignInRouterEvents }, _?: NonReducibleUnknown) => - (event as SignInRouterNextEvent)?.resource?.status === status || context.clerk?.client.signIn.status === status; + ({ context, event }: { context: SignInRouterContext; event?: SignInRouterEvents }, _?: NonReducibleUnknown) => + (event as SignInRouterNextEvent)?.resource?.status === status || context.clerk?.client.signIn.status === status; export const SignInRouterMachineId = 'SignInRouter'; @@ -131,6 +131,7 @@ export const SignInRouterMachine = setup({ case ERROR_CODES.ENTERPRISE_SSO_HOSTED_DOMAIN_MISMATCH: case ERROR_CODES.SAML_EMAIL_ADDRESS_DOMAIN_MISMATCH: case ERROR_CODES.ORGANIZATION_MEMBERSHIP_QUOTA_EXCEEDED_FOR_SSO: + case ERROR_CODES.SIGN_UP_RESTRICTED_WAITLIST: error = new ClerkElementsError(errorOrig.code, errorOrig.longMessage || ''); break; default: @@ -196,11 +197,10 @@ export const SignInRouterMachine = setup({ type: 'REDIRECT', params: { strategy: event.strategy, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signInUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signInUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignInUrl({ params: context.router?.searchParams(), }), @@ -213,11 +213,10 @@ export const SignInRouterMachine = setup({ params: { strategy: 'saml', identifier: context.formRef.getSnapshot().context.fields.get('identifier')?.value, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signInUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signInUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignInUrl({ params: context.router?.searchParams(), }), @@ -230,11 +229,10 @@ export const SignInRouterMachine = setup({ params: { strategy: 'enterprise_sso', identifier: context.formRef.getSnapshot().context.fields.get('identifier')?.value, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signInUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signInUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignInUrl({ params: context.router?.searchParams(), }), @@ -371,7 +369,6 @@ export const SignInRouterMachine = setup({ }, Start: { tags: ['step:start'], - exit: 'clearFormErrors', invoke: { id: 'start', src: 'startMachine', @@ -402,21 +399,21 @@ export const SignInRouterMachine = setup({ NEXT: [ { guard: 'isComplete', - actions: 'setActive', + actions: ['setActive', 'clearFormErrors'], }, { guard: 'statusNeedsFirstFactor', - actions: { type: 'navigateInternal', params: { path: '/continue' } }, + actions: ["clearFormErrors", { type: "navigateInternal", params: { path: "/continue" } }], target: 'FirstFactor', }, { guard: 'statusNeedsSecondFactor', - actions: { type: 'navigateInternal', params: { path: '/continue' } }, + actions: ["clearFormErrors", { type: "navigateInternal", params: { path: "/continue" } }], target: 'SecondFactor', }, { guard: 'statusNeedsNewPassword', - actions: { type: 'navigateInternal', params: { path: '/reset-password' } }, + actions: ["clearFormErrors", { type: "navigateInternal", params: { path: "/reset-password" } }], target: 'ResetPassword', }, ], diff --git a/packages/elements/src/internals/machines/sign-up/router.machine.ts b/packages/elements/src/internals/machines/sign-up/router.machine.ts index f3dcf09b8cc..2f6b7ca31e8 100644 --- a/packages/elements/src/internals/machines/sign-up/router.machine.ts +++ b/packages/elements/src/internals/machines/sign-up/router.machine.ts @@ -31,13 +31,13 @@ export type TSignUpRouterMachine = typeof SignUpRouterMachine; const isCurrentPath = (path: `/${string}`) => - ({ context }: { context: SignUpRouterContext }, _params?: NonReducibleUnknown) => - context.router?.match(path) ?? false; + ({ context }: { context: SignUpRouterContext }, _params?: NonReducibleUnknown) => + context.router?.match(path) ?? false; const needsStatus = (status: SignUpStatus) => - ({ context, event }: { context: SignUpRouterContext; event?: SignUpRouterEvents }, _?: NonReducibleUnknown) => - (event as SignUpRouterNextEvent)?.resource?.status === status || context.clerk?.client?.signUp?.status === status; + ({ context, event }: { context: SignUpRouterContext; event?: SignUpRouterEvents }, _?: NonReducibleUnknown) => + (event as SignUpRouterNextEvent)?.resource?.status === status || context.clerk?.client?.signUp?.status === status; export const SignUpRouterMachine = setup({ actors: { @@ -116,6 +116,7 @@ export const SignUpRouterMachine = setup({ case ERROR_CODES.ENTERPRISE_SSO_HOSTED_DOMAIN_MISMATCH: case ERROR_CODES.SAML_EMAIL_ADDRESS_DOMAIN_MISMATCH: case ERROR_CODES.ORGANIZATION_MEMBERSHIP_QUOTA_EXCEEDED_FOR_SSO: + case ERROR_CODES.SIGN_UP_RESTRICTED_WAITLIST: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion error = new ClerkElementsError(errorOrig.code, errorOrig.longMessage!); break; @@ -197,11 +198,10 @@ export const SignUpRouterMachine = setup({ type: 'REDIRECT', params: { strategy: event.strategy, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signUpUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signUpUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignUpUrl({ params: context.router?.searchParams(), }), @@ -214,11 +214,10 @@ export const SignUpRouterMachine = setup({ params: { strategy: 'saml', emailAddress: context.formRef.getSnapshot().context.fields.get('emailAddress')?.value, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signUpUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signUpUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignUpUrl({ params: context.router?.searchParams(), }), @@ -231,11 +230,10 @@ export const SignUpRouterMachine = setup({ params: { strategy: 'enterprise_sso', emailAddress: context.formRef.getSnapshot().context.fields.get('emailAddress')?.value, - redirectUrl: `${ - context.router?.mode === ROUTING.virtual - ? context.clerk.__unstable__environment?.displayConfig.signUpUrl - : context.router?.basePath - }${SSO_CALLBACK_PATH_ROUTE}`, + redirectUrl: `${context.router?.mode === ROUTING.virtual + ? context.clerk.__unstable__environment?.displayConfig.signUpUrl + : context.router?.basePath + }${SSO_CALLBACK_PATH_ROUTE}`, redirectUrlComplete: context.clerk.buildAfterSignUpUrl({ params: context.router?.searchParams(), }), @@ -357,7 +355,6 @@ export const SignUpRouterMachine = setup({ }, Start: { tags: ['step:start'], - exit: 'clearFormErrors', invoke: { id: 'start', src: 'startMachine', @@ -381,22 +378,22 @@ export const SignUpRouterMachine = setup({ NEXT: [ { guard: 'isStatusComplete', - actions: ['setActive', 'delayedReset'], + actions: ['setActive', 'delayedReset', 'clearFormErrors'], }, { guard: and(['hasTicket', 'statusNeedsContinue']), - actions: { type: 'navigateInternal', params: { path: '/' } }, + actions: ['clearFormErrors', { type: 'navigateInternal', params: { path: '/' } }], target: 'Start', reenter: true, }, { guard: 'statusNeedsVerification', target: 'Verification', - actions: { type: 'navigateInternal', params: { path: '/verify' } }, + actions: ['clearFormErrors', { type: 'navigateInternal', params: { path: '/verify' } }], }, { guard: 'statusNeedsContinue', - actions: { type: 'navigateInternal', params: { path: '/continue' } }, + actions: ['clearFormErrors', { type: 'navigateInternal', params: { path: '/continue' } }], target: 'Continue', }, ],