Skip to content

Commit 637b791

Browse files
committed
fix(clerk-js): Update type of resetPasswordFlow in SignInResource
1 parent 3fbf8e7 commit 637b791

File tree

13 files changed

+88
-37
lines changed

13 files changed

+88
-37
lines changed

packages/clerk-js/src/core/resources/SignIn.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export class SignIn extends BaseResource implements SignInResource {
5050
identifier: string | null = null;
5151
createdSessionId: string | null = null;
5252
userData: UserData = {};
53-
resetPasswordFlow = false;
5453

5554
constructor(data: SignInJSON | null = null) {
5655
super();
@@ -94,13 +93,10 @@ export class SignIn extends BaseResource implements SignInResource {
9493
break;
9594
case 'reset_password_code':
9695
if (factor.emailAddressId) {
97-
config = { emailAddressId: factor.emailAddressId } as ResetPasswordCodeFactorConfig;
98-
}
99-
if (factor.phoneNumberId) {
100-
config = {
101-
phoneNumberId: factor.phoneNumberId,
102-
} as ResetPasswordCodeFactorConfig;
96+
config = { emailAddressId: factor?.emailAddressId } as ResetPasswordCodeFactorConfig;
97+
break;
10398
}
99+
config = { phoneNumberId: factor?.phoneNumberId } as ResetPasswordCodeFactorConfig;
104100
break;
105101
default:
106102
clerkInvalidStrategy('SignIn.prepareFirstFactor', factor.strategy);
@@ -235,7 +231,6 @@ export class SignIn extends BaseResource implements SignInResource {
235231
this.secondFactorVerification = new Verification(data.second_factor_verification);
236232
this.createdSessionId = data.created_session_id;
237233
this.userData = deepSnakeToCamel(data.user_data) as UserData;
238-
this.resetPasswordFlow = data.reset_password_flow;
239234
}
240235
return this;
241236
}

packages/clerk-js/src/ui/components/OrganizationProfile/InviteMembersForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => {
5353
});
5454

5555
const {
56-
props: { errorText, ...restEmailAddressProps },
56+
props: { errorText, hasLostFocus, setError, isSuccessful, setSuccessful, ...restEmailAddressProps },
5757
} = emailAddressField;
5858

5959
const roleField = useFormControl('role', 'basic_member', {

packages/clerk-js/src/ui/components/SignIn/ResetPasswordSuccess.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ const useActivateSession = () => {
1414

1515
useEffect(() => {
1616
let timeoutId: ReturnType<typeof setTimeout>;
17-
if (new URLSearchParams(queryString).has('createdSessionId')) {
18-
const createdSessionId = new URLSearchParams(queryString).get('createdSessionId');
17+
const queryParams = new URLSearchParams(queryString);
18+
const createdSessionId = queryParams.get('createdSessionId');
19+
if (createdSessionId) {
1920
timeoutId = setTimeout(() => {
2021
void setActive({ session: createdSessionId, beforeEmit: navigateAfterSignIn });
2122
}, 2000);
@@ -28,7 +29,7 @@ const useActivateSession = () => {
2829
};
2930
});
3031
};
31-
export const _ResetPassword = () => {
32+
export const _ResetPasswordSuccess = () => {
3233
const card = useCardState();
3334
useActivateSession();
3435
return (
@@ -60,4 +61,4 @@ export const _ResetPassword = () => {
6061
);
6162
};
6263

63-
export const ResetPasswordSuccess = withRedirectToHomeSingleSessionGuard(withCardStateProvider(_ResetPassword));
64+
export const ResetPasswordSuccess = withRedirectToHomeSingleSessionGuard(withCardStateProvider(_ResetPasswordSuccess));

packages/clerk-js/src/ui/components/SignIn/SignInFactorOneForgotPasswordCard.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,28 @@ import { SignInFactorOneCodeForm } from './SignInFactorOneCodeForm';
88
type SignInForgotPasswordCardProps = SignInFactorOneCodeCard & { factor: ResetPasswordCodeFactor };
99

1010
export const SignInFactorOneForgotPasswordCard = (props: SignInForgotPasswordCardProps) => {
11-
const { supportedFirstFactors, identifier } = useCoreSignIn();
12-
13-
const strategy = supportedFirstFactors.find(factor => (factor as any)?.safeIdentifier === identifier)?.strategy;
14-
const isPhoneStrategy = strategy === 'phone_code';
11+
const { supportedFirstFactors } = useCoreSignIn();
12+
const resetPasswordFactor = supportedFirstFactors.find(({ strategy }) => strategy === 'reset_password_code') as
13+
| ResetPasswordCodeFactor
14+
| undefined;
1515

1616
return (
1717
<Flow.Part part='resetPassword'>
1818
<SignInFactorOneCodeForm
1919
{...props}
2020
showAlternativeMethods={false}
2121
cardTitle={
22-
isPhoneStrategy
22+
resetPasswordFactor?.phoneNumberId
2323
? localizationKeys('signIn.forgotPassword.title_phone')
2424
: localizationKeys('signIn.forgotPassword.title_email')
2525
}
2626
cardSubtitle={localizationKeys('signIn.forgotPassword.subtitle')}
2727
formTitle={localizationKeys('signIn.forgotPassword.formTitle')}
28-
formSubtitle={localizationKeys('signIn.forgotPassword.formSubtitle')}
28+
formSubtitle={
29+
resetPasswordFactor?.phoneNumberId
30+
? localizationKeys('signIn.forgotPassword.formSubtitle_phone')
31+
: localizationKeys('signIn.forgotPassword.formSubtitle_email')
32+
}
2933
resendButton={localizationKeys('signIn.forgotPassword.resendButton')}
3034
/>
3135
</Flow.Part>

packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ResetPasswordCodeFactor } from '@clerk/types';
12
import React from 'react';
23

34
import { clerkInvalidFAPIResponse } from '../../../core/errors';
@@ -10,7 +11,7 @@ import { handleError, useFormControl } from '../../utils';
1011

1112
type SignInFactorOnePasswordProps = {
1213
onShowAlternativeMethodsClick: React.MouseEventHandler;
13-
onFactorPrepare: () => void;
14+
onFactorPrepare: (f: ResetPasswordCodeFactor) => void;
1415
};
1516

1617
export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => {
@@ -48,6 +49,17 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
4849
.catch(err => handleError(err, [passwordControl], card.setError));
4950
};
5051

52+
const resetPasswordFactor = signIn.supportedFirstFactors.find(
53+
({ strategy }) => strategy === 'reset_password_code',
54+
) as ResetPasswordCodeFactor | undefined;
55+
56+
const goToForgotPassword = () => {
57+
resetPasswordFactor &&
58+
onFactorPrepare({
59+
...resetPasswordFactor,
60+
});
61+
};
62+
5163
return (
5264
<Flow.Part part='password'>
5365
<Card>
@@ -83,7 +95,7 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps)
8395
{...passwordControl.props}
8496
autoFocus
8597
actionLabel={localizationKeys('formFieldAction__forgotPassword')}
86-
onActionClicked={onFactorPrepare}
98+
onActionClicked={resetPasswordFactor ? goToForgotPassword : onShowAlternativeMethodsClick}
8799
/>
88100
</Form.ControlRow>
89101
<Form.SubmitButton />

packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoBackupCodeCard.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { SignInResource } from '@clerk/types';
12
import React from 'react';
23

34
import { clerkInvalidFAPIResponse } from '../../../core/errors';
@@ -27,15 +28,21 @@ export const SignInFactorTwoBackupCodeCard = (props: SignInFactorTwoBackupCodeCa
2728
isRequired: true,
2829
});
2930

31+
const isResettingPassword = (resource: SignInResource) =>
32+
resource.firstFactorVerification?.strategy === 'reset_password_code' &&
33+
resource.firstFactorVerification?.status === 'verified';
34+
3035
const handleBackupCodeSubmit: React.FormEventHandler = e => {
3136
e.preventDefault();
3237
return signIn
3338
.attemptSecondFactor({ strategy: 'backup_code', code: codeControl.value })
3439
.then(res => {
3540
switch (res.status) {
3641
case 'complete':
37-
if (signIn.resetPasswordFlow) {
38-
return navigate(`../reset-password-success?createdSessionId=${res.createdSessionId}`);
42+
if (isResettingPassword(res) && res.createdSessionId) {
43+
const queryParams = new URLSearchParams();
44+
queryParams.set('createdSessionId', res.createdSessionId);
45+
return navigate(`../reset-password-success?${queryParams.toString()}`);
3946
}
4047
return setActive({ session: res.createdSessionId, beforeEmit: navigateAfterSignIn });
4148
default:
@@ -52,7 +59,7 @@ export const SignInFactorTwoBackupCodeCard = (props: SignInFactorTwoBackupCodeCa
5259
<Header.Title localizationKey={localizationKeys('signIn.backupCodeMfa.title')} />
5360
<Header.Subtitle
5461
localizationKey={
55-
signIn?.resetPasswordFlow
62+
isResettingPassword(signIn)
5663
? localizationKeys('signIn.forgotPassword.subtitle')
5764
: localizationKeys('signIn.backupCodeMfa.subtitle', {
5865
applicationName: displayConfig.applicationName,

packages/clerk-js/src/ui/components/SignIn/SignInFactorTwoCodeForm.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { PhoneCodeFactor, SignInResource, TOTPFactor } from '@clerk/types';
22
import React from 'react';
33

44
import { clerkInvalidFAPIResponse } from '../../../core/errors';
5-
import { useCoreSignIn, useOptions } from '../../contexts';
5+
import { useCoreClerk, useCoreSignIn, useOptions, useSignInContext } from '../../contexts';
66
import { localizationKeys, Text } from '../../customizables';
77
import type { VerificationCodeCardProps } from '../../elements';
88
import { useCardState, VerificationCodeCard } from '../../elements';
@@ -29,6 +29,8 @@ type SignInFactorTwoCodeFormProps = SignInFactorTwoCodeCard & {
2929
export const SignInFactorTwoCodeForm = (props: SignInFactorTwoCodeFormProps) => {
3030
const signIn = useCoreSignIn();
3131
const card = useCardState();
32+
const { navigateAfterSignIn } = useSignInContext();
33+
const { setActive } = useCoreClerk();
3234
const { navigate } = useRouter();
3335
const supportEmail = useSupportEmail();
3436
const { experimental_enableClerkImages } = useOptions();
@@ -50,14 +52,23 @@ export const SignInFactorTwoCodeForm = (props: SignInFactorTwoCodeFormProps) =>
5052
}
5153
: undefined;
5254

55+
const isResettingPassword = (resource: SignInResource) =>
56+
resource.firstFactorVerification?.strategy === 'reset_password_code' &&
57+
resource.firstFactorVerification?.status === 'verified';
58+
5359
const action: VerificationCodeCardProps['onCodeEntryFinishedAction'] = (code, resolve, reject) => {
5460
signIn
5561
.attemptSecondFactor({ strategy: props.factor.strategy, code })
5662
.then(async res => {
5763
await resolve();
5864
switch (res.status) {
5965
case 'complete':
60-
return navigate(`../reset-password-success?createdSessionId=${res.createdSessionId}`);
66+
if (isResettingPassword(res) && res.createdSessionId) {
67+
const queryParams = new URLSearchParams();
68+
queryParams.set('createdSessionId', res.createdSessionId);
69+
return navigate(`../reset-password-success?${queryParams.toString()}`);
70+
}
71+
return setActive({ session: res.createdSessionId, beforeEmit: navigateAfterSignIn });
6172
default:
6273
return console.error(clerkInvalidFAPIResponse(res.status, supportEmail));
6374
}
@@ -68,7 +79,9 @@ export const SignInFactorTwoCodeForm = (props: SignInFactorTwoCodeFormProps) =>
6879
return (
6980
<VerificationCodeCard
7081
cardTitle={props.cardTitle}
71-
cardSubtitle={signIn?.resetPasswordFlow ? localizationKeys('signIn.forgotPassword.subtitle') : props.cardSubtitle}
82+
cardSubtitle={
83+
isResettingPassword(signIn) ? localizationKeys('signIn.forgotPassword.subtitle') : props.cardSubtitle
84+
}
7285
formTitle={props.formTitle}
7386
formSubtitle={props.formSubtitle}
7487
resendButton={props.resendButton}
@@ -80,12 +93,13 @@ export const SignInFactorTwoCodeForm = (props: SignInFactorTwoCodeFormProps) =>
8093
}
8194
onShowAlternativeMethodsClicked={props.onShowAlternativeMethodsClicked}
8295
>
83-
{/* TODO: Conditionally render + localization */}
84-
<Text
85-
localizationKey={'We need to verify your identity before resetting your password.'}
86-
variant='smallRegular'
87-
colorScheme='neutral'
88-
/>
96+
{isResettingPassword(signIn) && (
97+
<Text
98+
localizationKey={localizationKeys('signIn.resetPasswordMfa.detailsLabel')}
99+
variant='smallRegular'
100+
colorScheme='neutral'
101+
/>
102+
)}
89103
</VerificationCodeCard>
90104
);
91105
};

packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function _SignInStart(): JSX.Element {
6161
placeholder: localizationKeys('formFieldInputPlaceholder__password') as any,
6262
});
6363

64-
const identifierField = useFormControl('identifier', 'pantelis+1@clerk.dev', {
64+
const identifierField = useFormControl('identifier', '', {
6565
...currentIdentifier,
6666
isRequired: true,
6767
});

packages/clerk-js/src/ui/utils/test/fixtureHelpers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
124124
...(supportEmailCode ? [{ strategy: 'email_code', safe_identifier: identifier || 'n*****@clerk.dev' }] : []),
125125
...(supportEmailLink ? [{ strategy: 'email_link', safe_identifier: identifier || 'n*****@clerk.dev' }] : []),
126126
],
127+
reset_password_flow: {
128+
has_new_password: false,
129+
comm_type: null,
130+
},
127131
user_data: { ...(createUserFixture() as any) },
128132
} as SignInJSON;
129133
};
@@ -138,6 +142,10 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
138142
...(supportPassword ? [{ strategy: 'password' }] : []),
139143
...(supportPhoneCode ? [{ strategy: 'phone_code', safe_identifier: '+30********90' }] : []),
140144
],
145+
reset_password_flow: {
146+
has_new_password: false,
147+
comm_type: null,
148+
},
141149
user_data: { ...(createUserFixture() as any) },
142150
} as SignInJSON;
143151
};
@@ -153,6 +161,10 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
153161
...(supportTotp ? [{ strategy: 'totp', safe_identifier: identifier || 'n*****@clerk.dev' }] : []),
154162
...(supportBackupCode ? [{ strategy: 'backup_code', safe_identifier: identifier || 'n*****@clerk.dev' }] : []),
155163
],
164+
reset_password_flow: {
165+
has_new_password: false,
166+
comm_type: null,
167+
},
156168
user_data: { ...(createUserFixture() as any) },
157169
} as SignInJSON;
158170
};

packages/localizations/src/en-US.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { LocalizationResource } from '@clerk/types';
2+
import { LocalizationValue } from '@clerk/types';
23

34
const commonTexts = {
45
signIn: {
@@ -146,7 +147,10 @@ export const enUS: LocalizationResource = {
146147
resetPassword: {
147148
title: 'Reset Password',
148149
formButtonPrimary: 'Reset Password',
149-
successMessage: 'Your password was successfully changes. Now signing you in, please wait a moment.',
150+
successMessage: 'Your password was successfully changed. Signing you in, please wait a moment.',
151+
},
152+
resetPasswordMfa: {
153+
detailsLabel: 'We need to verify your identity before resetting your password.',
150154
},
151155
emailCode: {
152156
title: 'Check your email',

0 commit comments

Comments
 (0)