mirror of
https://github.com/zhigang1992/xverse-web-extension.git
synced 2026-01-12 18:02:19 +08:00
Terence/fix pw screen (#676)
* remove duplicate * remove error message * remove unnecessary props * fix boolean logic * remove e2e logic check * restore message (opps) * fixup button jumping * Update src/app/components/passwordInput/index.styled.ts Co-authored-by: Den <36603049+dhriaznov@users.noreply.github.com> * remove --------- Co-authored-by: Den <36603049+dhriaznov@users.noreply.github.com>
This commit is contained in:
@@ -34,7 +34,7 @@ export const ButtonsContainer = styled.div<{
|
||||
flexDirection: props.$stackButtonAlignment ? 'column-reverse' : 'row',
|
||||
alignItems: props.$stackButtonAlignment ? 'center' : 'flex-end',
|
||||
flex: 1,
|
||||
marginTop: props.$ifError ? props.theme.spacing(30) : props.theme.spacing(40),
|
||||
marginTop: props.$ifError ? props.theme.space.xxxl : props.theme.space.xxxxl,
|
||||
marginBottom: props.theme.space.m,
|
||||
}));
|
||||
|
||||
@@ -47,8 +47,9 @@ export const StyledButton = styled.button({
|
||||
},
|
||||
});
|
||||
|
||||
export const PasswordStrengthContainer = styled.div((props) => ({
|
||||
export const PasswordStrengthContainer = styled.div<{ $visibility: boolean }>((props) => ({
|
||||
...props.theme.typography.body_medium_m,
|
||||
visibility: props.$visibility ? 'visible' : 'hidden',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
|
||||
@@ -20,8 +20,6 @@ import {
|
||||
StyledButton,
|
||||
} from './index.styled';
|
||||
|
||||
const REQUIRED_PASSWORD_LENGTH = 5;
|
||||
|
||||
enum PasswordStrength {
|
||||
NoScore,
|
||||
PoorScore,
|
||||
@@ -43,7 +41,6 @@ type Props = {
|
||||
checkPasswordStrength?: boolean;
|
||||
stackButtonAlignment?: boolean;
|
||||
loading?: boolean;
|
||||
createPasswordFlow?: boolean;
|
||||
autoFocus?: boolean;
|
||||
};
|
||||
|
||||
@@ -59,18 +56,16 @@ function PasswordInput({
|
||||
checkPasswordStrength,
|
||||
stackButtonAlignment = false,
|
||||
loading,
|
||||
createPasswordFlow,
|
||||
autoFocus = false,
|
||||
}: Props): JSX.Element {
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'CREATE_PASSWORD_SCREEN' });
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation('translation', { keyPrefix: 'CREATE_PASSWORD_SCREEN' });
|
||||
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
||||
const [passwordStrength, setPasswordStrength] = useState<PasswordStrength>(
|
||||
PasswordStrength.NoScore,
|
||||
);
|
||||
|
||||
const { score } = zxcvbn(enteredPassword);
|
||||
const enteredPasswordLength = enteredPassword.length;
|
||||
const [error, setError] = useState<string>(passwordError ?? '');
|
||||
const transition = useTransition(passwordStrength, {
|
||||
from: {
|
||||
opacity: 0,
|
||||
@@ -79,6 +74,33 @@ function PasswordInput({
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
const enteredPasswordLength = enteredPassword.length;
|
||||
let passwordStrengthLabel;
|
||||
if (!enteredPassword) {
|
||||
passwordStrengthLabel = {
|
||||
color: theme.colors.white_600,
|
||||
width: '0',
|
||||
message: '',
|
||||
};
|
||||
} else if (score <= PasswordStrength.WeakScore) {
|
||||
passwordStrengthLabel = {
|
||||
color: theme.colors.feedback.error,
|
||||
width: '20%',
|
||||
message: <p style={{ color: theme.colors.feedback.error }}>{t('PASSWORD_STRENGTH_WEAK')}</p>,
|
||||
};
|
||||
} else if (score <= PasswordStrength.AverageScore) {
|
||||
passwordStrengthLabel = {
|
||||
color: theme.colors.feedback.caution,
|
||||
width: '50%',
|
||||
message: <p>{t('PASSWORD_STRENGTH_MEDIUM')}</p>,
|
||||
};
|
||||
} else {
|
||||
passwordStrengthLabel = {
|
||||
color: theme.colors.feedback.success,
|
||||
width: '100%',
|
||||
message: <p>{t('PASSWORD_STRENGTH_STRONG')}</p>,
|
||||
};
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const keyDownHandler = (event) => {
|
||||
@@ -86,7 +108,6 @@ function PasswordInput({
|
||||
event.key === 'Enter' &&
|
||||
document.activeElement?.id === 'password-input' &&
|
||||
!!enteredPassword &&
|
||||
enteredPasswordLength >= REQUIRED_PASSWORD_LENGTH &&
|
||||
(checkPasswordStrength ? score >= PasswordStrength.AverageScore : true)
|
||||
) {
|
||||
event.preventDefault();
|
||||
@@ -97,94 +118,16 @@ function PasswordInput({
|
||||
return () => {
|
||||
document.removeEventListener('keydown', keyDownHandler);
|
||||
};
|
||||
}, [enteredPassword]);
|
||||
|
||||
useEffect(() => {
|
||||
if (passwordError) {
|
||||
setError(passwordError);
|
||||
return;
|
||||
}
|
||||
if (enteredPassword && !!createPasswordFlow && score <= PasswordStrength.WeakScore) {
|
||||
setError(t('PASSWORD_STRENGTH_ERROR'));
|
||||
return;
|
||||
}
|
||||
setError('');
|
||||
}, [passwordError, enteredPassword]);
|
||||
}, [checkPasswordStrength, enteredPassword, enteredPasswordLength, handleContinue, score]);
|
||||
|
||||
useEffect(() => {
|
||||
if (enteredPassword !== '') {
|
||||
setPasswordStrength(score);
|
||||
}
|
||||
|
||||
return () => {
|
||||
setPasswordStrength(PasswordStrength.NoScore);
|
||||
};
|
||||
}, [enteredPassword, setPasswordStrength]);
|
||||
|
||||
const handleTogglePasswordView = () => {
|
||||
setIsPasswordVisible(!isPasswordVisible);
|
||||
};
|
||||
|
||||
const handlePasswordChange = (event: React.FormEvent<HTMLInputElement>) => {
|
||||
setEnteredPassword(event.currentTarget.value);
|
||||
};
|
||||
|
||||
const renderStrengthBar = () => {
|
||||
if (enteredPassword !== '') {
|
||||
if (
|
||||
enteredPasswordLength <= REQUIRED_PASSWORD_LENGTH ||
|
||||
score <= PasswordStrength.WeakScore
|
||||
) {
|
||||
return (
|
||||
<PasswordStrengthContainer>
|
||||
<span>{t('PASSWORD_STRENGTH_LABEL')}</span>
|
||||
<StrengthBar $strengthColor={theme.colors.feedback.error} $strengthWidth="20%">
|
||||
{transition((style) => (
|
||||
<animated.div style={style} />
|
||||
))}
|
||||
</StrengthBar>
|
||||
<p style={{ color: theme.colors.feedback.error }}>{t('PASSWORD_STRENGTH_WEAK')}</p>
|
||||
</PasswordStrengthContainer>
|
||||
);
|
||||
}
|
||||
|
||||
if (score <= PasswordStrength.AverageScore) {
|
||||
return (
|
||||
<PasswordStrengthContainer>
|
||||
<span>{t('PASSWORD_STRENGTH_LABEL')}</span>
|
||||
{transition((style) => (
|
||||
<StrengthBar $strengthColor={theme.colors.feedback.caution} $strengthWidth="50%">
|
||||
<animated.div style={style} />
|
||||
</StrengthBar>
|
||||
))}
|
||||
<p>{t('PASSWORD_STRENGTH_MEDIUM')}</p>
|
||||
</PasswordStrengthContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PasswordStrengthContainer>
|
||||
<span>{t('PASSWORD_STRENGTH_LABEL')}</span>
|
||||
{transition((style) => (
|
||||
<StrengthBar $strengthColor={theme.colors.feedback.success} $strengthWidth="100%">
|
||||
<animated.div style={style} />
|
||||
</StrengthBar>
|
||||
))}
|
||||
<p>{t('PASSWORD_STRENGTH_STRONG')}</p>
|
||||
</PasswordStrengthContainer>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<PasswordStrengthContainer>
|
||||
<span>{t('PASSWORD_STRENGTH_LABEL')}</span>
|
||||
<StrengthBar $strengthColor={theme.colors.white_600} $strengthWidth="0">
|
||||
{transition((style) => (
|
||||
<animated.div style={style} />
|
||||
))}
|
||||
</StrengthBar>
|
||||
</PasswordStrengthContainer>
|
||||
);
|
||||
};
|
||||
}, [enteredPassword, score, setPasswordStrength]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@@ -198,10 +141,10 @@ function PasswordInput({
|
||||
id="password-input"
|
||||
type={isPasswordVisible ? 'text' : 'password'}
|
||||
value={enteredPassword}
|
||||
onChange={handlePasswordChange}
|
||||
onChange={(e) => setEnteredPassword(e.currentTarget.value)}
|
||||
autoFocus={autoFocus}
|
||||
complications={
|
||||
<StyledButton onClick={handleTogglePasswordView}>
|
||||
<StyledButton onClick={() => setIsPasswordVisible(!isPasswordVisible)}>
|
||||
<img
|
||||
src={isPasswordVisible ? Eye : EyeSlash}
|
||||
alt="toggle password visibility"
|
||||
@@ -209,11 +152,22 @@ function PasswordInput({
|
||||
/>
|
||||
</StyledButton>
|
||||
}
|
||||
feedback={error !== '' ? [{ message: error, variant: 'danger' }] : undefined}
|
||||
feedback={passwordError ? [{ message: passwordError, variant: 'danger' }] : undefined}
|
||||
hideClear
|
||||
/>
|
||||
{checkPasswordStrength ? renderStrengthBar() : null}
|
||||
<ButtonsContainer $stackButtonAlignment={stackButtonAlignment} $ifError={error !== ''}>
|
||||
<PasswordStrengthContainer $visibility={!!checkPasswordStrength}>
|
||||
<span>{t('PASSWORD_STRENGTH_LABEL')}</span>
|
||||
<StrengthBar
|
||||
$strengthColor={passwordStrengthLabel.color}
|
||||
$strengthWidth={passwordStrengthLabel.width}
|
||||
>
|
||||
{transition((style) => (
|
||||
<animated.div style={style} />
|
||||
))}
|
||||
</StrengthBar>
|
||||
{passwordStrengthLabel.message}
|
||||
</PasswordStrengthContainer>
|
||||
<ButtonsContainer $stackButtonAlignment={stackButtonAlignment} $ifError={!!passwordError}>
|
||||
<ButtonContainer $stackButtonAlignment={stackButtonAlignment}>
|
||||
<Button title={t('BACK_BUTTON')} onClick={handleBack} variant="secondary" type="button" />
|
||||
</ButtonContainer>
|
||||
|
||||
@@ -101,7 +101,6 @@ function CreatePassword(): JSX.Element {
|
||||
handleContinue={handleContinuePasswordCreation}
|
||||
handleBack={handleNewPasswordBack}
|
||||
checkPasswordStrength
|
||||
createPasswordFlow
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -129,7 +129,6 @@ function RestoreWallet(): JSX.Element {
|
||||
handleContinue={onNewPasswordContinue}
|
||||
handleBack={onNewPasswordBack}
|
||||
checkPasswordStrength
|
||||
createPasswordFlow
|
||||
autoFocus
|
||||
/>
|
||||
</PasswordContainer>,
|
||||
|
||||
@@ -93,7 +93,6 @@ function ChangePasswordScreen() {
|
||||
handleBack={handleBackButtonClick}
|
||||
checkPasswordStrength
|
||||
stackButtonAlignment
|
||||
createPasswordFlow
|
||||
autoFocus
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -594,7 +594,6 @@
|
||||
"PASSWORD_STRENGTH_WEAK": "Weak",
|
||||
"PASSWORD_STRENGTH_MEDIUM": "Medium",
|
||||
"PASSWORD_STRENGTH_STRONG": "Strong",
|
||||
"PASSWORD_STRENGTH_ERROR": "Your password should be at least 9 characters long. Use a mix of uppercase letters, lowercase letters, numbers, and symbols",
|
||||
"CONFIRM_PASSWORD_MATCH_ERROR": "Please make sure your passwords match",
|
||||
"INCORRECT_PASSWORD_ERROR": "Incorrect password"
|
||||
},
|
||||
|
||||
@@ -26,8 +26,6 @@ export default class Onboarding {
|
||||
|
||||
readonly inputPassword: Locator;
|
||||
|
||||
readonly errorMessage: Locator;
|
||||
|
||||
readonly errorMessage2: Locator;
|
||||
|
||||
readonly errorMessageSeedPhrase: Locator;
|
||||
@@ -89,7 +87,6 @@ export default class Onboarding {
|
||||
this.buttonSeedWords = page.locator('button[value]:not([value=""])');
|
||||
this.header = page.locator('#app h3');
|
||||
this.inputPassword = page.locator('input[type="password"]');
|
||||
this.errorMessage = page.locator('p').filter({ hasText: 'Your password should be at' });
|
||||
this.errorMessage2 = page.locator('p').filter({ hasText: 'Please make sure your' });
|
||||
this.errorMessageSeedPhrase = page.locator('p').filter({ hasText: 'Invalid seed phrase' });
|
||||
this.labelSecurityLevelWeak = page.locator('p').filter({ hasText: 'Weak' });
|
||||
@@ -186,7 +183,6 @@ export default class Onboarding {
|
||||
await expect(this.inputPassword).toBeVisible();
|
||||
await expect(this.buttonContinue).toBeVisible();
|
||||
await expect(this.buttonContinue).toBeDisabled();
|
||||
await expect(this.errorMessage).toBeHidden();
|
||||
await expect(this.labelSecurityLevelWeak).toBeHidden();
|
||||
await expect(this.labelSecurityLevelMedium).toBeHidden();
|
||||
await expect(this.labelSecurityLevelStrong).toBeHidden();
|
||||
@@ -263,15 +259,6 @@ export default class Onboarding {
|
||||
// Fill in the password input field with the specified password.
|
||||
await this.inputPassword.fill(password);
|
||||
|
||||
// Check if an error message is expected to be visible.
|
||||
if (expectations.errorMessageVisible) {
|
||||
// If yes, verify that the error message element is visible.
|
||||
await expect(this.errorMessage).toBeVisible();
|
||||
} else {
|
||||
// If not, verify that the error message element is hidden.
|
||||
await expect(this.errorMessage).toBeHidden();
|
||||
}
|
||||
|
||||
// Define a mapping of security levels to their corresponding label elements.
|
||||
const visibilityChecks = {
|
||||
Weak: this.labelSecurityLevelWeak,
|
||||
|
||||
Reference in New Issue
Block a user