parent
543a992d98
commit
3df07c10fa
@ -1,22 +1,74 @@
|
|||||||
import React, { useCallback } from 'react';
|
import zxcvbn from 'zxcvbn';
|
||||||
import { Icon, Input } from 'semantic-ui-react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Icon, Input, Progress } from 'semantic-ui-react';
|
||||||
import { useToggle } from '../../../hooks';
|
import { useToggle } from '../../../hooks';
|
||||||
|
|
||||||
const InputPassword = React.forwardRef((props, ref) => {
|
import styles from './InputPassword.module.css';
|
||||||
|
|
||||||
|
const STRENGTH_SCORE_COLORS = ['red', 'orange', 'yellow', 'olive', 'green'];
|
||||||
|
|
||||||
|
const InputPassword = React.forwardRef(
|
||||||
|
({ value, withStrengthBar, minStrengthScore, className, ...props }, ref) => {
|
||||||
const [isVisible, toggleVisible] = useToggle();
|
const [isVisible, toggleVisible] = useToggle();
|
||||||
|
|
||||||
|
const strengthScore = useMemo(() => {
|
||||||
|
if (!withStrengthBar) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zxcvbn(value).score;
|
||||||
|
}, [value, withStrengthBar]);
|
||||||
|
|
||||||
const handleToggleClick = useCallback(() => {
|
const handleToggleClick = useCallback(() => {
|
||||||
toggleVisible();
|
toggleVisible();
|
||||||
}, [toggleVisible]);
|
}, [toggleVisible]);
|
||||||
|
|
||||||
|
const inputProps = {
|
||||||
|
...props,
|
||||||
|
ref,
|
||||||
|
type: isVisible ? 'text' : 'password',
|
||||||
|
icon: <Icon link name={isVisible ? 'eye' : 'eye slash'} onClick={handleToggleClick} />,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!withStrengthBar) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
{...inputProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className={className}>
|
||||||
<Input
|
<Input
|
||||||
{...props} // eslint-disable-line react/jsx-props-no-spreading
|
{...inputProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||||
ref={ref}
|
error={!!value && strengthScore < minStrengthScore}
|
||||||
type={isVisible ? 'text' : 'password'}
|
/>
|
||||||
icon={<Icon link name={isVisible ? 'eye' : 'eye slash'} onClick={handleToggleClick} />}
|
<Progress
|
||||||
|
value={value ? strengthScore + 1 : 0}
|
||||||
|
total={5}
|
||||||
|
color={STRENGTH_SCORE_COLORS[strengthScore]}
|
||||||
|
size="tiny"
|
||||||
|
className={styles.strengthBar}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
InputPassword.propTypes = {
|
||||||
|
value: PropTypes.string.isRequired,
|
||||||
|
withStrengthBar: PropTypes.bool,
|
||||||
|
minStrengthScore: PropTypes.number,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
InputPassword.defaultProps = {
|
||||||
|
withStrengthBar: false,
|
||||||
|
minStrengthScore: 2,
|
||||||
|
className: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
export default React.memo(InputPassword);
|
export default React.memo(InputPassword);
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
.strengthBar {
|
||||||
|
margin: 4px 0 0 !important;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
@ -1,10 +1,8 @@
|
|||||||
const PASSWORD_REGEX = /^(?=.*[A-Za-z])(?=.*\d).+$/;
|
import zxcvbn from 'zxcvbn';
|
||||||
|
|
||||||
const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/;
|
const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/;
|
||||||
|
|
||||||
export const isPassword = (string) => {
|
export const isPassword = (string) => zxcvbn(string).score >= 2; // TODO: move to config
|
||||||
return string.length >= 6 && PASSWORD_REGEX.test(string);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isUsername = (string) => {
|
export const isUsername = (string) =>
|
||||||
return string.length >= 3 && string.length <= 16 && USERNAME_REGEX.test(string);
|
string.length >= 3 && string.length <= 16 && USERNAME_REGEX.test(string);
|
||||||
};
|
|
||||||
|
|||||||
Loading…
Reference in New Issue