mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor(experience): avoid disabled button for continue button (#6271)
This commit is contained in:
parent
e9a70ba6d9
commit
216859a906
16 changed files with 49 additions and 21 deletions
|
@ -1,4 +1,5 @@
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import VerificationCodeInput from '@/components/VerificationCode';
|
import VerificationCodeInput from '@/components/VerificationCode';
|
||||||
|
@ -18,17 +19,28 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const TotpCodeVerification = ({ flow }: Props) => {
|
const TotpCodeVerification = ({ flow }: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [codeInput, setCodeInput] = useState<string[]>([]);
|
const [codeInput, setCodeInput] = useState<string[]>([]);
|
||||||
|
const [inputErrorMessage, setInputErrorMessage] = useState<string>();
|
||||||
|
|
||||||
const errorCallback = useCallback(() => {
|
const errorCallback = useCallback(() => {
|
||||||
setCodeInput([]);
|
setCodeInput([]);
|
||||||
|
setInputErrorMessage(undefined);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { errorMessage, onSubmit } = useTotpCodeVerification(flow, errorCallback);
|
const { errorMessage: submitErrorMessage, onSubmit } = useTotpCodeVerification(
|
||||||
|
flow,
|
||||||
|
errorCallback
|
||||||
|
);
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
|
||||||
|
const errorMessage = inputErrorMessage ?? submitErrorMessage;
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
async (code: string[]) => {
|
async (code: string[]) => {
|
||||||
|
setInputErrorMessage(undefined);
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
await onSubmit(code.join(''));
|
await onSubmit(code.join(''));
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
|
@ -55,8 +67,12 @@ const TotpCodeVerification = ({ flow }: Props) => {
|
||||||
type="primary"
|
type="primary"
|
||||||
className={styles.continueButton}
|
className={styles.continueButton}
|
||||||
isLoading={isSubmitting}
|
isLoading={isSubmitting}
|
||||||
isDisabled={!isCodeReady(codeInput)}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (!isCodeReady(codeInput)) {
|
||||||
|
setInputErrorMessage(t('error.invalid_passcode'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void handleSubmit(codeInput);
|
void handleSubmit(codeInput);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -23,6 +23,8 @@ type Props = {
|
||||||
|
|
||||||
const VerificationCode = ({ flow, identifier, className, hasPasswordButton, target }: Props) => {
|
const VerificationCode = ({ flow, identifier, className, hasPasswordButton, target }: Props) => {
|
||||||
const [codeInput, setCodeInput] = useState<string[]>([]);
|
const [codeInput, setCodeInput] = useState<string[]>([]);
|
||||||
|
const [inputErrorMessage, setInputErrorMessage] = useState<string>();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isCodeInputReady = useMemo(
|
const isCodeInputReady = useMemo(
|
||||||
|
@ -34,13 +36,16 @@ const VerificationCode = ({ flow, identifier, className, hasPasswordButton, targ
|
||||||
|
|
||||||
const errorCallback = useCallback(() => {
|
const errorCallback = useCallback(() => {
|
||||||
setCodeInput([]);
|
setCodeInput([]);
|
||||||
|
setInputErrorMessage(undefined);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { errorMessage, clearErrorMessage, onSubmit } = useVerificationCode(
|
const {
|
||||||
identifier,
|
errorMessage: submitErrorMessage,
|
||||||
target,
|
clearErrorMessage,
|
||||||
errorCallback
|
onSubmit,
|
||||||
);
|
} = useVerificationCode(identifier, target, errorCallback);
|
||||||
|
|
||||||
|
const errorMessage = inputErrorMessage ?? submitErrorMessage;
|
||||||
|
|
||||||
const { seconds, isRunning, onResendVerificationCode } = useResendVerificationCode(
|
const { seconds, isRunning, onResendVerificationCode } = useResendVerificationCode(
|
||||||
flow,
|
flow,
|
||||||
|
@ -52,6 +57,8 @@ const VerificationCode = ({ flow, identifier, className, hasPasswordButton, targ
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
async (code: string[]) => {
|
async (code: string[]) => {
|
||||||
|
setInputErrorMessage(undefined);
|
||||||
|
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
|
|
||||||
await onSubmit(
|
await onSubmit(
|
||||||
|
@ -110,10 +117,14 @@ const VerificationCode = ({ flow, identifier, className, hasPasswordButton, targ
|
||||||
<Button
|
<Button
|
||||||
title="action.continue"
|
title="action.continue"
|
||||||
type="primary"
|
type="primary"
|
||||||
isDisabled={!isCodeInputReady}
|
|
||||||
isLoading={isSubmitting}
|
isLoading={isSubmitting}
|
||||||
className={styles.continueButton}
|
className={styles.continueButton}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (!isCodeInputReady) {
|
||||||
|
setInputErrorMessage(t('error.invalid_passcode'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void handleSubmit(codeInput);
|
void handleSubmit(codeInput);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,6 +24,7 @@ const useErrorHandler = () => {
|
||||||
const logtoError = await error.response.json<RequestErrorBody>();
|
const logtoError = await error.response.json<RequestErrorBody>();
|
||||||
|
|
||||||
const { code, message } = logtoError;
|
const { code, message } = logtoError;
|
||||||
|
|
||||||
const handler = errorHandlers?.[code] ?? errorHandlers?.global;
|
const handler = errorHandlers?.[code] ?? errorHandlers?.global;
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: 'Die Email ist ungültig',
|
invalid_email: 'Die Email ist ungültig',
|
||||||
invalid_phone: 'Die Telefonnummer ist ungültig',
|
invalid_phone: 'Die Telefonnummer ist ungültig',
|
||||||
passwords_do_not_match: 'Passwörter stimmen nicht überein',
|
passwords_do_not_match: 'Passwörter stimmen nicht überein',
|
||||||
invalid_passcode: 'Der Bestätigungscode ist ungültig',
|
invalid_passcode: 'Der Bestätigungscode ist ungültig.',
|
||||||
invalid_connector_auth: 'Die Autorisierung ist ungültig',
|
invalid_connector_auth: 'Die Autorisierung ist ungültig',
|
||||||
invalid_connector_request: 'Connector Daten sind ungültig',
|
invalid_connector_request: 'Connector Daten sind ungültig',
|
||||||
unknown: 'Unbekannter Fehler. Versuche es später noch einmal.',
|
unknown: 'Unbekannter Fehler. Versuche es später noch einmal.',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: 'The email is invalid',
|
invalid_email: 'The email is invalid',
|
||||||
invalid_phone: 'The phone number is invalid',
|
invalid_phone: 'The phone number is invalid',
|
||||||
passwords_do_not_match: 'Your passwords don’t match. Please try again.',
|
passwords_do_not_match: 'Your passwords don’t match. Please try again.',
|
||||||
invalid_passcode: 'The verification code is invalid',
|
invalid_passcode: 'The verification code is invalid.',
|
||||||
invalid_connector_auth: 'The authorization is invalid',
|
invalid_connector_auth: 'The authorization is invalid',
|
||||||
invalid_connector_request: 'The connector data is invalid',
|
invalid_connector_request: 'The connector data is invalid',
|
||||||
unknown: 'Unknown error. Please try again later.',
|
unknown: 'Unknown error. Please try again later.',
|
||||||
|
|
|
@ -12,7 +12,7 @@ const error = {
|
||||||
invalid_email: 'El correo electrónico no es válido',
|
invalid_email: 'El correo electrónico no es válido',
|
||||||
invalid_phone: 'El número de teléfono no es válido',
|
invalid_phone: 'El número de teléfono no es válido',
|
||||||
passwords_do_not_match: 'Las contraseñas no coinciden. Por favor intente de nuevo',
|
passwords_do_not_match: 'Las contraseñas no coinciden. Por favor intente de nuevo',
|
||||||
invalid_passcode: 'El código de verificación no es válido',
|
invalid_passcode: 'El código de verificación no es válido.',
|
||||||
invalid_connector_auth: 'La autorización no es válida',
|
invalid_connector_auth: 'La autorización no es válida',
|
||||||
invalid_connector_request: 'Los datos del conector no son válidos',
|
invalid_connector_request: 'Los datos del conector no son válidos',
|
||||||
unknown: 'Error desconocido. Por favor intente de nuevo más tarde.',
|
unknown: 'Error desconocido. Por favor intente de nuevo más tarde.',
|
||||||
|
|
|
@ -13,7 +13,7 @@ const error = {
|
||||||
invalid_email: "L'email n'est pas valide",
|
invalid_email: "L'email n'est pas valide",
|
||||||
invalid_phone: "Le numéro de téléphone n'est pas valide",
|
invalid_phone: "Le numéro de téléphone n'est pas valide",
|
||||||
passwords_do_not_match: 'Les mots de passe ne correspondent pas',
|
passwords_do_not_match: 'Les mots de passe ne correspondent pas',
|
||||||
invalid_passcode: 'Le code est invalide',
|
invalid_passcode: 'Le code est invalide.',
|
||||||
invalid_connector_auth: "L'autorisation n'est pas valide",
|
invalid_connector_auth: "L'autorisation n'est pas valide",
|
||||||
invalid_connector_request: 'Les données du connecteur ne sont pas valides',
|
invalid_connector_request: 'Les données du connecteur ne sont pas valides',
|
||||||
unknown: 'Erreur inconnue. Veuillez réessayer plus tard.',
|
unknown: 'Erreur inconnue. Veuillez réessayer plus tard.',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: "L'email non è valida",
|
invalid_email: "L'email non è valida",
|
||||||
invalid_phone: 'Il numero di telefono non è valido',
|
invalid_phone: 'Il numero di telefono non è valido',
|
||||||
passwords_do_not_match: 'Le password non corrispondono. Per favore prova di nuovo.',
|
passwords_do_not_match: 'Le password non corrispondono. Per favore prova di nuovo.',
|
||||||
invalid_passcode: 'Il codice di verifica non è valido',
|
invalid_passcode: 'Il codice di verifica non è valido.',
|
||||||
invalid_connector_auth: "L'autorizzazione è invalida",
|
invalid_connector_auth: "L'autorizzazione è invalida",
|
||||||
invalid_connector_request: 'I dati del connettore non sono validi',
|
invalid_connector_request: 'I dati del connettore non sono validi',
|
||||||
unknown: 'Errore sconosciuto. Si prega di riprovare più tardi.',
|
unknown: 'Errore sconosciuto. Si prega di riprovare più tardi.',
|
||||||
|
|
|
@ -12,7 +12,7 @@ const error = {
|
||||||
invalid_email: 'メールアドレスが無効です',
|
invalid_email: 'メールアドレスが無効です',
|
||||||
invalid_phone: '電話番号が無効です',
|
invalid_phone: '電話番号が無効です',
|
||||||
passwords_do_not_match: 'パスワードが一致しません。もう一度お試しください。',
|
passwords_do_not_match: 'パスワードが一致しません。もう一度お試しください。',
|
||||||
invalid_passcode: '検証コードが無効です',
|
invalid_passcode: '検証コードが無効です。',
|
||||||
invalid_connector_auth: '認証が無効です',
|
invalid_connector_auth: '認証が無効です',
|
||||||
invalid_connector_request: 'コネクターデータが無効です',
|
invalid_connector_request: 'コネクターデータが無効です',
|
||||||
unknown: '不明なエラーが発生しました。後でもう一度お試しください。',
|
unknown: '不明なエラーが発生しました。後でもう一度お試しください。',
|
||||||
|
|
|
@ -12,7 +12,7 @@ const error = {
|
||||||
invalid_email: 'Nieprawidłowy adres e-mail',
|
invalid_email: 'Nieprawidłowy adres e-mail',
|
||||||
invalid_phone: 'Nieprawidłowy numer telefonu',
|
invalid_phone: 'Nieprawidłowy numer telefonu',
|
||||||
passwords_do_not_match: 'Hasła nie pasują do siebie. Proszę spróbuj ponownie.',
|
passwords_do_not_match: 'Hasła nie pasują do siebie. Proszę spróbuj ponownie.',
|
||||||
invalid_passcode: 'Nieprawidłowy kod weryfikacyjny',
|
invalid_passcode: 'Nieprawidłowy kod weryfikacyjny.',
|
||||||
invalid_connector_auth: 'Nieprawidłowa autoryzacja',
|
invalid_connector_auth: 'Nieprawidłowa autoryzacja',
|
||||||
invalid_connector_request: 'Nieprawidłowe dane konektora',
|
invalid_connector_request: 'Nieprawidłowe dane konektora',
|
||||||
unknown: 'Nieznany błąd. Proszę spróbuj ponownie później.',
|
unknown: 'Nieznany błąd. Proszę spróbuj ponownie później.',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: 'O e-mail é inválido',
|
invalid_email: 'O e-mail é inválido',
|
||||||
invalid_phone: 'O número de telefone é inválido',
|
invalid_phone: 'O número de telefone é inválido',
|
||||||
passwords_do_not_match: 'Suas senhas não correspondem. Por favor, tente novamente.',
|
passwords_do_not_match: 'Suas senhas não correspondem. Por favor, tente novamente.',
|
||||||
invalid_passcode: 'O código de verificação é inválido',
|
invalid_passcode: 'O código de verificação é inválido.',
|
||||||
invalid_connector_auth: 'A autorização é inválida',
|
invalid_connector_auth: 'A autorização é inválida',
|
||||||
invalid_connector_request: 'Os dados do conector são inválidos',
|
invalid_connector_request: 'Os dados do conector são inválidos',
|
||||||
unknown: 'Erro desconhecido. Por favor, tente novamente mais tarde.',
|
unknown: 'Erro desconhecido. Por favor, tente novamente mais tarde.',
|
||||||
|
|
|
@ -12,7 +12,7 @@ const error = {
|
||||||
invalid_email: 'Электронная почта указана неправильно',
|
invalid_email: 'Электронная почта указана неправильно',
|
||||||
invalid_phone: 'Номер телефона указан неправильно',
|
invalid_phone: 'Номер телефона указан неправильно',
|
||||||
passwords_do_not_match: 'Пароли не совпадают. Пожалуйста, попробуйте еще раз.',
|
passwords_do_not_match: 'Пароли не совпадают. Пожалуйста, попробуйте еще раз.',
|
||||||
invalid_passcode: 'Неправильный код подтверждения',
|
invalid_passcode: 'Неправильный код подтверждения.',
|
||||||
invalid_connector_auth: 'Авторизация недействительна',
|
invalid_connector_auth: 'Авторизация недействительна',
|
||||||
invalid_connector_request: 'Данные коннектора недействительны.',
|
invalid_connector_request: 'Данные коннектора недействительны.',
|
||||||
unknown: 'Неизвестная ошибка. Пожалуйста, повторите попытку позднее.',
|
unknown: 'Неизвестная ошибка. Пожалуйста, повторите попытку позднее.',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: 'E-posta adresi geçersiz',
|
invalid_email: 'E-posta adresi geçersiz',
|
||||||
invalid_phone: 'Telefon numarası geçersiz',
|
invalid_phone: 'Telefon numarası geçersiz',
|
||||||
passwords_do_not_match: 'Şifreler eşleşmiyor',
|
passwords_do_not_match: 'Şifreler eşleşmiyor',
|
||||||
invalid_passcode: 'Doğrulama kodu geçersiz',
|
invalid_passcode: 'Doğrulama kodu geçersiz.',
|
||||||
invalid_connector_auth: 'Yetki geçersiz',
|
invalid_connector_auth: 'Yetki geçersiz',
|
||||||
invalid_connector_request: 'Bağlayıcı veri geçersiz',
|
invalid_connector_request: 'Bağlayıcı veri geçersiz',
|
||||||
unknown: 'Bilinmeyen hata. Lütfen daha sonra tekrar deneyiniz.',
|
unknown: 'Bilinmeyen hata. Lütfen daha sonra tekrar deneyiniz.',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: '无效的邮箱',
|
invalid_email: '无效的邮箱',
|
||||||
invalid_phone: '无效的手机号',
|
invalid_phone: '无效的手机号',
|
||||||
passwords_do_not_match: '两次输入的密码不一致,请重试。',
|
passwords_do_not_match: '两次输入的密码不一致,请重试。',
|
||||||
invalid_passcode: '无效的验证码',
|
invalid_passcode: '无效的验证码。',
|
||||||
invalid_connector_auth: '登录失败',
|
invalid_connector_auth: '登录失败',
|
||||||
invalid_connector_request: '无效的登录请求',
|
invalid_connector_request: '无效的登录请求',
|
||||||
unknown: '未知错误,请稍后重试。',
|
unknown: '未知错误,请稍后重试。',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: '無效的電子郵件',
|
invalid_email: '無效的電子郵件',
|
||||||
invalid_phone: '無效的手機號碼',
|
invalid_phone: '無效的手機號碼',
|
||||||
passwords_do_not_match: '兩次輸入的密碼不一致,請重試。',
|
passwords_do_not_match: '兩次輸入的密碼不一致,請重試。',
|
||||||
invalid_passcode: '無效的驗證碼',
|
invalid_passcode: '無效的驗證碼。',
|
||||||
invalid_connector_auth: '登錄失敗',
|
invalid_connector_auth: '登錄失敗',
|
||||||
invalid_connector_request: '無效的登錄請求',
|
invalid_connector_request: '無效的登錄請求',
|
||||||
unknown: '未知錯誤,請稍後重試。',
|
unknown: '未知錯誤,請稍後重試。',
|
||||||
|
|
|
@ -11,7 +11,7 @@ const error = {
|
||||||
invalid_email: '無效的郵箱',
|
invalid_email: '無效的郵箱',
|
||||||
invalid_phone: '無效的手機號',
|
invalid_phone: '無效的手機號',
|
||||||
passwords_do_not_match: '兩次輸入的密碼不一致,請重試。',
|
passwords_do_not_match: '兩次輸入的密碼不一致,請重試。',
|
||||||
invalid_passcode: '無效的驗證碼',
|
invalid_passcode: '無效的驗證碼。',
|
||||||
invalid_connector_auth: '登錄失敗',
|
invalid_connector_auth: '登錄失敗',
|
||||||
invalid_connector_request: '無效的登錄請求',
|
invalid_connector_request: '無效的登錄請求',
|
||||||
unknown: '未知錯誤,請稍後重試。',
|
unknown: '未知錯誤,請稍後重試。',
|
||||||
|
|
Loading…
Reference in a new issue