mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
fix(ui): fix some of the bug bash issues (#1053)
* fix(ui): clear error message when passcode resend clear error message when passcode resend; * fix(ui): directly throw account not exist in social bind flow directly throw account not exsit in social bind flow * fix(ui): fix toast and loading light border fix toast and loading light border * fix(ui): add auto focus to input add auto focus to input * style(ui): adjust font & button size adjust font & button size * fix(ui): cr fix cr fix
This commit is contained in:
parent
02059ffa66
commit
db1b6d247a
13 changed files with 48 additions and 16 deletions
|
@ -19,6 +19,8 @@
|
|||
|
||||
body {
|
||||
background-color: var(--color-base);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: auto;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
.button {
|
||||
@include _.flex-row;
|
||||
justify-content: center;
|
||||
padding: _.unit(3);
|
||||
height: 44px;
|
||||
padding: 0 _.unit(3);
|
||||
border-radius: var(--radius);
|
||||
font: var(--font-body-bold);
|
||||
cursor: pointer;
|
||||
|
@ -18,7 +19,7 @@
|
|||
}
|
||||
|
||||
.small {
|
||||
min-width: 44px;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.primary {
|
||||
|
|
|
@ -74,6 +74,7 @@ const PhoneInput = ({
|
|||
{countrySelector}
|
||||
<input
|
||||
ref={inputReference}
|
||||
autoFocus
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
value={nationalNumber}
|
||||
|
|
|
@ -35,6 +35,6 @@
|
|||
|
||||
:global(body.desktop) {
|
||||
.container {
|
||||
border: _.border(var(--color-divider));
|
||||
border: _.border(var(--color-toast-border));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ const Passcode = ({ name, className, value, length = defaultLength, error, onCha
|
|||
name={`${name}_${index}`}
|
||||
data-id={index}
|
||||
value={codes[index]}
|
||||
type="text"
|
||||
type="text" // Number type allows 'e' as input but returns empty value
|
||||
inputMode="numeric"
|
||||
maxLength={2} // Allow overwrite input
|
||||
autoComplete="off"
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
:global(body.desktop) {
|
||||
.toast {
|
||||
border: _.border(var(--color-divider));
|
||||
border: _.border(var(--color-toast-border));
|
||||
padding: _.unit(3) _.unit(4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,9 +79,9 @@ const CreateAccount = ({ className }: Props) => {
|
|||
return (
|
||||
<form className={classNames(styles.form, className)}>
|
||||
<Input
|
||||
autoFocus
|
||||
className={styles.inputField}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
placeholder={t('input.username')}
|
||||
{...fieldRegister('username', usernameValidation)}
|
||||
onClear={() => {
|
||||
|
@ -92,7 +92,6 @@ const CreateAccount = ({ className }: Props) => {
|
|||
className={styles.inputField}
|
||||
name="password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
placeholder={t('input.password')}
|
||||
{...fieldRegister('password', passwordValidation)}
|
||||
onClear={() => {
|
||||
|
@ -103,7 +102,6 @@ const CreateAccount = ({ className }: Props) => {
|
|||
className={styles.inputField}
|
||||
name="confirm_password"
|
||||
type="password"
|
||||
autoComplete="current-password"
|
||||
placeholder={t('input.confirm_password')}
|
||||
{...fieldRegister('confirmPassword', (confirmPassword) =>
|
||||
confirmPasswordValidation(fieldValue.password, confirmPassword)
|
||||
|
|
|
@ -64,6 +64,8 @@ const PasscodeValidation = ({ type, method, className, target }: Props) => {
|
|||
const { run: sendPassCode } = useApi(getSendPasscodeApi(type, method));
|
||||
|
||||
const resendPasscodeHandler = useCallback(async () => {
|
||||
setError(undefined);
|
||||
|
||||
const result = await sendPassCode(target);
|
||||
|
||||
if (result) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useState, useMemo, useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
|
@ -9,8 +9,10 @@ import Input from '@/components/Input';
|
|||
import TermsOfUse from '@/containers/TermsOfUse';
|
||||
import useApi, { ErrorHandlers } from '@/hooks/use-api';
|
||||
import useForm from '@/hooks/use-form';
|
||||
import { PageContext } from '@/hooks/use-page-context';
|
||||
import useTerms from '@/hooks/use-terms';
|
||||
import { UserFlow } from '@/types';
|
||||
import { UserFlow, SearchParameters } from '@/types';
|
||||
import { getSearchParameters } from '@/utils';
|
||||
import { emailValidation } from '@/utils/field-validations';
|
||||
|
||||
import PasswordlessConfirmModal from './PasswordlessConfirmModal';
|
||||
|
@ -28,6 +30,7 @@ type FieldState = {
|
|||
const defaultState: FieldState = { email: '' };
|
||||
|
||||
const EmailPasswordless = ({ type, className }: Props) => {
|
||||
const { setToast } = useContext(PageContext);
|
||||
const [showPasswordlessConfirmModal, setShowPasswordlessConfirmModal] = useState(false);
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
const navigate = useNavigate();
|
||||
|
@ -37,7 +40,16 @@ const EmailPasswordless = ({ type, className }: Props) => {
|
|||
|
||||
const errorHandlers: ErrorHandlers = useMemo(
|
||||
() => ({
|
||||
'user.email_not_exists': () => {
|
||||
'user.email_not_exists': (error) => {
|
||||
const socialToBind = getSearchParameters(location.search, SearchParameters.bindWithSocial);
|
||||
|
||||
// Directly display the error if user is trying to bind with social
|
||||
if (socialToBind) {
|
||||
setToast(error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setShowPasswordlessConfirmModal(true);
|
||||
},
|
||||
'user.email_exists_register': () => {
|
||||
|
@ -47,7 +59,7 @@ const EmailPasswordless = ({ type, className }: Props) => {
|
|||
setFieldErrors({ email: 'invalid_email' });
|
||||
},
|
||||
}),
|
||||
[setFieldErrors]
|
||||
[setFieldErrors, setToast]
|
||||
);
|
||||
|
||||
const sendPasscode = getSendPasscodeApi(type, 'email');
|
||||
|
@ -85,6 +97,7 @@ const EmailPasswordless = ({ type, className }: Props) => {
|
|||
<>
|
||||
<form className={classNames(styles.form, className)}>
|
||||
<Input
|
||||
autoFocus
|
||||
className={styles.inputField}
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useState, useMemo, useContext } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
|
@ -9,9 +9,11 @@ import { PhoneInput } from '@/components/Input';
|
|||
import TermsOfUse from '@/containers/TermsOfUse';
|
||||
import useApi, { ErrorHandlers } from '@/hooks/use-api';
|
||||
import useForm from '@/hooks/use-form';
|
||||
import { PageContext } from '@/hooks/use-page-context';
|
||||
import usePhoneNumber, { countryList } from '@/hooks/use-phone-number';
|
||||
import useTerms from '@/hooks/use-terms';
|
||||
import { UserFlow } from '@/types';
|
||||
import { UserFlow, SearchParameters } from '@/types';
|
||||
import { getSearchParameters } from '@/utils';
|
||||
|
||||
import PasswordlessConfirmModal from './PasswordlessConfirmModal';
|
||||
import * as styles from './index.module.scss';
|
||||
|
@ -28,6 +30,7 @@ type FieldState = {
|
|||
const defaultState: FieldState = { phone: '' };
|
||||
|
||||
const PhonePasswordless = ({ type, className }: Props) => {
|
||||
const { setToast } = useContext(PageContext);
|
||||
const [showPasswordlessConfirmModal, setShowPasswordlessConfirmModal] = useState(false);
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||
const { phoneNumber, setPhoneNumber, isValidPhoneNumber } = usePhoneNumber();
|
||||
|
@ -38,7 +41,16 @@ const PhonePasswordless = ({ type, className }: Props) => {
|
|||
|
||||
const errorHandlers: ErrorHandlers = useMemo(
|
||||
() => ({
|
||||
'user.phone_not_exists': () => {
|
||||
'user.phone_not_exists': (error) => {
|
||||
const socialToBind = getSearchParameters(location.search, SearchParameters.bindWithSocial);
|
||||
|
||||
// Directly display the error if user is trying to bind with social
|
||||
if (socialToBind) {
|
||||
setToast(error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setShowPasswordlessConfirmModal(true);
|
||||
},
|
||||
'user.phone_exists_register': () => {
|
||||
|
@ -48,7 +60,7 @@ const PhonePasswordless = ({ type, className }: Props) => {
|
|||
setFieldErrors({ phone: 'invalid_phone' });
|
||||
},
|
||||
}),
|
||||
[setFieldErrors]
|
||||
[setFieldErrors, setToast]
|
||||
);
|
||||
|
||||
const sendPasscode = getSendPasscodeApi(type, 'sms');
|
||||
|
|
|
@ -85,6 +85,7 @@ const UsernameSignin = ({ className }: Props) => {
|
|||
return (
|
||||
<form className={classNames(styles.form, className)}>
|
||||
<Input
|
||||
autoFocus
|
||||
className={styles.inputField}
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
|
|
|
@ -72,6 +72,7 @@ $font-family: -apple-system,
|
|||
@mixin colors-universal {
|
||||
--color-primary-button-text: #fff;
|
||||
--color-toast: #34353f;
|
||||
--color-toast-border: #444748;
|
||||
--color-overlay: rgba(0, 0, 0, 30%);
|
||||
// shadows
|
||||
--shadow-1: 0 4px 8px rgba(0, 0, 0, 8%);
|
||||
|
|
|
@ -47,6 +47,7 @@ $font-family: -apple-system,
|
|||
@mixin colors-universal {
|
||||
--color-primary-button-text: #fff;
|
||||
--color-toast: #34353f;
|
||||
--color-toast-border: #444748;
|
||||
--color-overlay: rgba(0, 0, 0, 30%);
|
||||
// shadows
|
||||
--shadow-2: 0 4px 12px rgba(0, 0, 0, 12%);
|
||||
|
|
Loading…
Reference in a new issue