Merge branch 'feature/62-auth-v10' into 'main'

Added a hide/show password button, password complexity check

See merge request discoursio/discoursio-webapp!86
This commit is contained in:
Igor 2023-05-11 17:20:40 +00:00
commit 384fe16671
6 changed files with 76 additions and 3 deletions

7
public/icons/eye-off.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512px" height="512px" viewBox="0 0 512 512">
<path
d="M255.66,112c-77.94,0-157.89,45.11-220.83,135.33a16,16,0,0,0-.27,17.77C82.92,340.8,161.8,400,255.66,400,348.5,400,429,340.62,477.45,264.75a16.14,16.14,0,0,0,0-17.47C428.89,172.28,347.8,112,255.66,112Z"
style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px" />
<circle cx="256" cy="256" r="80" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:32px" />
<line x1="100" y1="400" x2="400" y2="100" style="stroke:#000;stroke-width:32px"/>
</svg>

After

Width:  |  Height:  |  Size: 618 B

View File

@ -46,6 +46,9 @@
"Create Chat": "Create Chat", "Create Chat": "Create Chat",
"Create Group": "Create a group", "Create Group": "Create a group",
"Create account": "Create an account", "Create account": "Create an account",
"Password should be at least 8 characters": "Password should be at least 8 characters",
"Password should contain at least one number": "Password should contain at least one number",
"Password should contain at least one special character: !@#$%^&*": "Password should contain at least one special character: !@#$%^&*",
"Create post": "Create post", "Create post": "Create post",
"Date of Birth": "Date of Birth", "Date of Birth": "Date of Birth",
"Delete": "Delete", "Delete": "Delete",

View File

@ -48,6 +48,9 @@
"Create Chat": "Создать чат", "Create Chat": "Создать чат",
"Create Group": "Создать группу", "Create Group": "Создать группу",
"Create account": "Создать аккаунт", "Create account": "Создать аккаунт",
"Password should be at least 8 characters": "Пароль должен быть не менее 8 символов",
"Password should contain at least one number": "Пароль должен содержать хотя бы одну цифру",
"Password should contain at least one special character: !@#$%^&*": "Пароль должен содержать хотя бы один специальный символ: !@#$%^&*",
"Create post": "Создать публикацию", "Create post": "Создать публикацию",
"Date of Birth": "Дата рождения", "Date of Birth": "Дата рождения",
"Delete": "Удалить", "Delete": "Удалить",

View File

@ -113,6 +113,7 @@
font-weight: 700; font-weight: 700;
padding: 1.6rem !important; padding: 1.6rem !important;
width: 100%; width: 100%;
margin-top: 32px;
} }
.authControl { .authControl {
@ -148,6 +149,10 @@
line-height: 16px; line-height: 16px;
margin-bottom: 8px; margin-bottom: 8px;
&.registerPassword {
margin-bottom: -32px;
}
/* Red/500 */ /* Red/500 */
color: #d00820; color: #d00820;
@ -162,6 +167,26 @@
} }
} }
.passwordToggle {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
}
.passwordToggleIcon {
height: 1.6em;
display: inline-block;
margin-right: 0.2em;
max-width: 1.4em;
max-height: 1.4em;
transition: filter 0.2s;
vertical-align: middle;
}
.title { .title {
font-size: 26px; font-size: 26px;
line-height: 32px; line-height: 32px;

View File

@ -13,6 +13,7 @@ import { signSendLink } from '../../../stores/auth'
import { useSnackbar } from '../../../context/snackbar' import { useSnackbar } from '../../../context/snackbar'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { Icon } from '../../_shared/Icon'
type FormFields = { type FormFields = {
email: string email: string
@ -30,6 +31,7 @@ export const LoginForm = () => {
// TODO: better solution for interactive error messages // TODO: better solution for interactive error messages
const [isEmailNotConfirmed, setIsEmailNotConfirmed] = createSignal(false) const [isEmailNotConfirmed, setIsEmailNotConfirmed] = createSignal(false)
const [isLinkSent, setIsLinkSent] = createSignal(false) const [isLinkSent, setIsLinkSent] = createSignal(false)
const [showPassword, setShowPassword] = createSignal(false)
const { const {
actions: { showSnackbar } actions: { showSnackbar }
@ -143,17 +145,26 @@ export const LoginForm = () => {
<Show when={validationErrors().email}> <Show when={validationErrors().email}>
<div class={styles.validationError}>{validationErrors().email}</div> <div class={styles.validationError}>{validationErrors().email}</div>
</Show> </Show>
<div class="pretty-form__item"> <div class="pretty-form__item">
<input <input
id="password" id="password"
name="password" name="password"
autocomplete="password" autocomplete="password"
type="password" type={showPassword() ? 'text' : 'password'}
placeholder={t('Password')} placeholder={t('Password')}
onInput={(event) => handlePasswordInput(event.currentTarget.value)} onInput={(event) => handlePasswordInput(event.currentTarget.value)}
/> />
<label for="password">{t('Password')}</label> <label for="password">{t('Password')}</label>
<button
type="button"
class={styles.passwordToggle}
onClick={() => setShowPassword(!showPassword())}
>
<Icon class={styles.passwordToggleIcon} name={showPassword() ? 'eye-off' : 'eye'} />
</button>
</div> </div>
<Show when={validationErrors().password}> <Show when={validationErrors().password}>
<div class={styles.validationError}>{validationErrors().password}</div> <div class={styles.validationError}>{validationErrors().password}</div>
</Show> </Show>

View File

@ -44,8 +44,30 @@ export const RegisterForm = () => {
} }
} }
function isValidPassword(password) {
const minLength = 8
const hasNumber = /\d/
const hasSpecial = /[!@#$%^&*]/
if (password.length < minLength) {
return t('Password should be at least 8 characters')
}
if (!hasNumber.test(password)) {
return t('Password should contain at least one number')
}
if (!hasSpecial.test(password)) {
return t('Password should contain at least one special character: !@#$%^&*')
}
return null
}
const handlePasswordInput = (newPassword: string) => { const handlePasswordInput = (newPassword: string) => {
setValidationErrors(({ password: _notNeeded, ...rest }) => rest) const passwordError = isValidPassword(newPassword)
if (passwordError) {
setValidationErrors((errors) => ({ ...errors, password: passwordError }))
} else {
setValidationErrors(({ password: _notNeeded, ...rest }) => rest)
}
setPassword(newPassword) setPassword(newPassword)
} }
@ -176,7 +198,9 @@ export const RegisterForm = () => {
<label for="password">{t('Password')}</label> <label for="password">{t('Password')}</label>
</div> </div>
<Show when={validationErrors().password}> <Show when={validationErrors().password}>
<div class={styles.validationError}>{validationErrors().password}</div> <div class={clsx(styles.registerPassword, styles.validationError)}>
{validationErrors().password}
</div>
</Show> </Show>
<div> <div>