Skip to content

Commit bc5a8e3

Browse files
committed
fix(console): fix sign-in method can't removed bug
fix sign-in methods can't removed bug. Also add new integration tests
1 parent cdc1acb commit bc5a8e3

File tree

5 files changed

+563
-48
lines changed

5 files changed

+563
-48
lines changed

packages/console/src/pages/SignInExperience/PageContent/SignUpAndSignIn/SignInForm/SignInMethodEditBox/index.tsx

+32-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { SignInIdentifier } from '@logto/schemas';
1+
import { AlternativeSignUpIdentifier, SignInIdentifier } from '@logto/schemas';
22
import { conditional } from '@silverhand/essentials';
3+
import { useCallback } from 'react';
34
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
45
import { useTranslation } from 'react-i18next';
56

@@ -48,22 +49,49 @@ function SignInMethodEditBox() {
4849

4950
const {
5051
identifier: signUpIdentifier,
51-
identifiers: signUpIdentifiers,
52+
identifiers,
5253
password: isSignUpPasswordRequired,
5354
verify: isSignUpVerificationRequired,
5455
} = signUp;
5556

5657
const requiredSignInIdentifiers = signUpIdentifiersMapping[signUpIdentifier];
58+
const signUpIdentifiers = identifiers.map(({ identifier }) => identifier);
5759

5860
// TODO: Remove this dev feature guard when multi sign-up identifiers are launched
5961
const ignoredWarningConnectors = isDevFeaturesEnabled
60-
? getSignUpIdentifiersRequiredConnectors(signUpIdentifiers.map(({ identifier }) => identifier))
62+
? getSignUpIdentifiersRequiredConnectors(signUpIdentifiers)
6163
: getSignUpRequiredConnectorTypes(signUpIdentifier);
6264

6365
const signInIdentifierOptions = signInIdentifiers.filter((candidateIdentifier) =>
6466
fields.every(({ identifier }) => identifier !== candidateIdentifier)
6567
);
6668

69+
const isVerificationCodeCheckable = useCallback(
70+
(identifier: SignInIdentifier) => {
71+
if (identifier === SignInIdentifier.Username) {
72+
return false;
73+
}
74+
75+
if (isSignUpPasswordRequired) {
76+
return true;
77+
}
78+
79+
if (!isDevFeaturesEnabled) {
80+
return !isSignUpVerificationRequired;
81+
}
82+
83+
// If the sign-in identifier is also enabled for sign-up.
84+
const signUpVerificationRequired = signUpIdentifiers.some(
85+
(signUpIdentifier) =>
86+
signUpIdentifier === identifier ||
87+
signUpIdentifier === AlternativeSignUpIdentifier.EmailOrPhone
88+
);
89+
90+
return !signUpVerificationRequired;
91+
},
92+
[isSignUpPasswordRequired, isSignUpVerificationRequired, signUpIdentifiers]
93+
);
94+
6795
return (
6896
<div>
6997
<DragDropProvider>
@@ -116,9 +144,7 @@ function SignInMethodEditBox() {
116144
identifier !== SignInIdentifier.Username &&
117145
(isDevFeaturesEnabled || !isSignUpPasswordRequired)
118146
}
119-
isVerificationCodeCheckable={
120-
!(isSignUpVerificationRequired && !isSignUpPasswordRequired)
121-
}
147+
isVerificationCodeCheckable={isVerificationCodeCheckable(value.identifier)}
122148
isDeletable={
123149
isDevFeaturesEnabled || !requiredSignInIdentifiers.includes(identifier)
124150
}

packages/console/src/pages/SignInExperience/PageContent/SignUpAndSignIn/SignUpForm/SignUpForm.tsx

+10-36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AlternativeSignUpIdentifier, SignInIdentifier } from '@logto/schemas';
2-
import { useEffect, useMemo } from 'react';
2+
import { useCallback, useMemo } from 'react';
33
import { Controller, useFormContext, useWatch } from 'react-hook-form';
44
import { useTranslation } from 'react-i18next';
55

@@ -44,40 +44,11 @@ function SignUpForm() {
4444
};
4545
}, [signUpIdentifiers]);
4646

47-
// Should sync the sign-up identifier auth settings when the sign-up identifiers changed
48-
// TODO: need to check with designer
49-
useEffect(() => {
50-
// Only trigger the effect when the identifiers field is dirty
51-
const isIdentifiersDirty = dirtyFields.signUp?.identifiers;
52-
if (!isIdentifiersDirty) {
53-
return;
54-
}
55-
56-
const identifiers = signUpIdentifiers.map(({ identifier }) => identifier);
57-
if (identifiers.length === 0) {
58-
setValue('signUp.password', false);
59-
setValue('signUp.verify', false);
60-
return;
61-
}
62-
63-
if (identifiers.includes(SignInIdentifier.Username)) {
64-
setValue('signUp.password', true);
65-
}
66-
67-
// Disable verification when the primary identifier is username,
68-
// otherwise enable it for the rest of the identifiers (email, phone, emailOrPhone)
69-
setValue('signUp.verify', identifiers[0] !== SignInIdentifier.Username);
70-
}, [dirtyFields.signUp?.identifiers, setValue, signUpIdentifiers]);
71-
7247
// Sync sign-in methods when sign-up methods change
73-
useEffect(() => {
74-
// Only trigger the effect when the sign-up field is dirty
75-
const isIdentifiersDirty = dirtyFields.signUp;
76-
if (!isIdentifiersDirty) {
77-
return;
78-
}
79-
48+
const syncSignInMethods = useCallback(() => {
8049
const signInMethods = getValues('signIn.methods');
50+
const signUp = getValues('signUp');
51+
8152
const { password, identifiers } = signUp;
8253

8354
const enabledSignUpIdentifiers = identifiers.reduce<SignInIdentifier[]>(
@@ -129,7 +100,7 @@ function SignUpForm() {
129100
void trigger('signIn.methods');
130101
}, 0);
131102
}
132-
}, [dirtyFields.signUp, getValues, setValue, signUp, submitCount, trigger]);
103+
}, [getValues, setValue, submitCount, trigger]);
133104

134105
return (
135106
<Card>
@@ -138,7 +109,7 @@ function SignUpForm() {
138109
<FormFieldDescription>
139110
{t('sign_in_exp.sign_up_and_sign_in.sign_up.identifier_description')}
140111
</FormFieldDescription>
141-
<SignUpIdentifiersEditBox />
112+
<SignUpIdentifiersEditBox syncSignInMethods={syncSignInMethods} />
142113
</FormField>
143114
{shouldShowAuthenticationFields && (
144115
<FormField title="sign_in_exp.sign_up_and_sign_in.sign_up.sign_up_authentication">
@@ -153,7 +124,10 @@ function SignUpForm() {
153124
<Checkbox
154125
label={t('sign_in_exp.sign_up_and_sign_in.sign_up.set_a_password_option')}
155126
checked={value}
156-
onChange={onChange}
127+
onChange={(value) => {
128+
onChange(value);
129+
syncSignInMethods();
130+
}}
157131
/>
158132
)}
159133
/>

packages/console/src/pages/SignInExperience/PageContent/SignUpAndSignIn/SignUpForm/SignUpIdentifiersEditBox/index.tsx

+47-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
type SignUpIdentifier,
55
} from '@logto/schemas';
66
import { t } from 'i18next';
7-
import { useMemo } from 'react';
7+
import { useCallback, useMemo } from 'react';
88
import { Controller, useFieldArray, useFormContext, useWatch } from 'react-hook-form';
99

1010
import { DragDropProvider, DraggableItem } from '@/ds-components/DragDrop';
@@ -29,8 +29,15 @@ const emailOrPhoneOption = {
2929

3030
const signUpIdentifierOptions = [...signInIdentifierOptions, emailOrPhoneOption];
3131

32-
function SignUpIdentifiersEditBox() {
33-
const { control } = useFormContext<SignInExperienceForm>();
32+
type Props = {
33+
/**
34+
* Sync the sign-in methods when the sign-up settings change.
35+
*/
36+
readonly syncSignInMethods: () => void;
37+
};
38+
39+
function SignUpIdentifiersEditBox({ syncSignInMethods }: Props) {
40+
const { control, getValues, setValue } = useFormContext<SignInExperienceForm>();
3441

3542
const signUpIdentifiers = useWatch({ control, name: 'signUp.identifiers' });
3643

@@ -41,6 +48,37 @@ function SignUpIdentifiersEditBox() {
4148
name: 'signUp.identifiers',
4249
});
4350

51+
// Revalidate the primary identifier authentication fields when the identifiers change
52+
const onSignUpIdentifiersChange = useCallback(() => {
53+
const identifiers = getValues('signUp.identifiers').map(({ identifier }) => identifier);
54+
setValue('signUp.verify', identifiers[0] !== SignInIdentifier.Username);
55+
syncSignInMethods();
56+
}, [getValues, setValue, syncSignInMethods]);
57+
58+
const onDeleteSignUpIdentifier = useCallback(() => {
59+
const identifiers = getValues('signUp.identifiers').map(({ identifier }) => identifier);
60+
61+
if (identifiers.length === 0) {
62+
setValue('signUp.password', false);
63+
setValue('signUp.verify', false);
64+
// Password changed need to sync sign-in methods
65+
syncSignInMethods();
66+
return;
67+
}
68+
69+
onSignUpIdentifiersChange();
70+
}, [getValues, onSignUpIdentifiersChange, setValue, syncSignInMethods]);
71+
72+
const onAppendSignUpIdentifier = useCallback(
73+
(identifier: SignUpIdentifier) => {
74+
if (identifier === SignInIdentifier.Username) {
75+
setValue('signUp.password', true);
76+
}
77+
onSignUpIdentifiersChange();
78+
},
79+
[onSignUpIdentifiersChange, setValue]
80+
);
81+
4482
const options = useMemo<
4583
Array<{
4684
value: SignUpIdentifier;
@@ -89,7 +127,10 @@ function SignUpIdentifiersEditBox() {
89127
key={id}
90128
id={id}
91129
sortIndex={index}
92-
moveItem={swap}
130+
moveItem={(dragIndex, hoverIndex) => {
131+
swap(dragIndex, hoverIndex);
132+
onSignUpIdentifiersChange();
133+
}}
93134
className={styles.draggleItemContainer}
94135
>
95136
<Controller
@@ -121,6 +162,7 @@ function SignUpIdentifiersEditBox() {
121162
errorMessage={error?.message}
122163
onDelete={() => {
123164
remove(index);
165+
onDeleteSignUpIdentifier();
124166
}}
125167
/>
126168
)}
@@ -135,6 +177,7 @@ function SignUpIdentifiersEditBox() {
135177
hasSelectedIdentifiers={signUpIdentifiers.length > 0}
136178
onSelected={(identifier) => {
137179
append({ identifier });
180+
onAppendSignUpIdentifier(identifier);
138181
}}
139182
/>
140183
</div>

0 commit comments

Comments
 (0)