Skip to content

Commit

Permalink
feat(clerk-js,shared): Add a navigateWithError utility for SignIn
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Pitsilos committed Nov 3, 2023
1 parent 7f7b4cb commit a6b4569
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 2 deletions.
8 changes: 8 additions & 0 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
BeforeEmitCallback,
BuildUrlWithAuthParams,
Clerk as ClerkInterface,
ClerkAPIError,
ClerkOptions,
ClientResource,
CreateOrganizationParams,
Expand Down Expand Up @@ -160,6 +161,7 @@ export default class Clerk implements ClerkInterface {
public __internal_country?: string | null;
public readonly frontendApi: string;
public readonly publishableKey?: string;
public __internal_last_error?: ClerkAPIError | null;

#domain: DomainOrProxyUrl['domain'];
#proxyUrl: DomainOrProxyUrl['proxyUrl'];
Expand Down Expand Up @@ -1187,6 +1189,12 @@ export default class Clerk implements ClerkInterface {
}
};

get __internal_last_error(): ClerkAPIError | null {
const value = this.__internal_last_error;
this.__internal_last_error = null;
return value;
}

updateClient = (newClient: ClientResource): void => {
if (!this.client) {
// This is the first time client is being
Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/src/core/resources/Error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
isKnownError,
isMagicLinkError,
isMetamaskError,
isUserLockedError,
MagicLinkError,
MagicLinkErrorCode,
parseError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isUserLockedError } from '@clerk/shared/error';
import type { ResetPasswordCodeFactor } from '@clerk/types';
import React from 'react';

Expand All @@ -10,6 +11,7 @@ import { useRouter } from '../../router/RouteContext';
import { handleError, useFormControl } from '../../utils';
import { HavingTrouble } from './HavingTrouble';
import { useResetPasswordFactor } from './useResetPasswordFactor';
import { navigateWithError } from './utils';

type SignInFactorOnePasswordProps = {
onForgotPasswordMethodClick: React.MouseEventHandler | undefined;
Expand Down Expand Up @@ -53,6 +55,7 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
const { navigate } = useRouter();
const [showHavingTrouble, setShowHavingTrouble] = React.useState(false);
const toggleHavingTrouble = React.useCallback(() => setShowHavingTrouble(s => !s), [setShowHavingTrouble]);
const Clerk = useCoreClerk();

const goBack = () => {
return navigate('../');
Expand All @@ -72,7 +75,13 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
return console.error(clerkInvalidFAPIResponse(res.status, supportEmail));
}
})
.catch(err => handleError(err, [passwordControl], card.setError));
.catch(err => {
if (isUserLockedError(err)) {
return navigateWithError(Clerk, navigate, '..', err.errors[0]);
}

handleError(err, [passwordControl], card.setError);
});
};

if (showHavingTrouble) {
Expand Down
6 changes: 6 additions & 0 deletions packages/clerk-js/src/ui/components/SignIn/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { titleize } from '@clerk/shared';
import type { PreferredSignInStrategy, SignInFactor, SignInResource, SignInStrategy } from '@clerk/types';

import type { Clerk } from '../../../core/resources/internal';
import { PREFERRED_SIGN_IN_STRATEGIES } from '../../common/constants';
import { otpPrefFactorComparator, passwordPrefFactorComparator } from './strategies/factorSortingUtils';

Expand Down Expand Up @@ -134,3 +135,8 @@ export function determineStartingSignInSecondFactor(secondFactors: SignInFactor[
const resetPasswordStrategies: SignInStrategy[] = ['reset_password_phone_code', 'reset_password_email_code'];
export const isResetPasswordStrategy = (strategy: SignInStrategy | string | null | undefined) =>
!!strategy && resetPasswordStrategies.includes(strategy as SignInStrategy);

export function navigateWithError(clerk: Clerk, navigate: (to: string) => Promise<unknown>, to: string, err) {
clerk.__internal_last_error = err;
return navigate(to);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ type CardStateCtxValue = {
const [CardStateCtx, _useCardState] = createContextAndHook<CardStateCtxValue>('CardState');

const CardStateProvider = (props: React.PropsWithChildren<any>) => {
const { translateError } = useLocalizations();

const [state, setState] = useSafeState<State>({
status: 'idle',
metadata: undefined,
error: undefined,
error: translateError(window?.Clerk.__internal_last_error),
});

const value = React.useMemo(() => ({ value: { state, setState } }), [state, setState]);
Expand Down
9 changes: 9 additions & 0 deletions packages/shared/src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export function isMetamaskError(err: any): err is MetamaskError {
return 'code' in err && [4001, 32602, 32603].includes(err.code) && 'message' in err;
}

export function isUserLockedError(err: any) {
return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'user_locked';
}

export function parseErrors(data: ClerkAPIErrorJSON[] = []): ClerkAPIError[] {
return data.length > 0 ? data.map(parseError) : [];
}
Expand Down Expand Up @@ -242,10 +246,15 @@ export type ErrorThrowerOptions = {

export interface ErrorThrower {
setPackageName(options: ErrorThrowerOptions): ErrorThrower;

setMessages(options: ErrorThrowerOptions): ErrorThrower;

throwInvalidPublishableKeyError(params: { key?: string }): never;

throwInvalidFrontendApiError(params: { key?: string }): never;

throwInvalidProxyUrl(params: { url?: string }): never;

throwMissingPublishableKeyError(): never;
}

Expand Down

0 comments on commit a6b4569

Please sign in to comment.