();
+ const [isConsentLoading, setIsConsentLoading] = useState(false);
+
const asyncGetConsentInfo = useApi(getConsentInfo);
const consentHandler = useCallback(async () => {
+ setIsConsentLoading(true);
const [error, result] = await asyncConsent(selectedOrganization?.id);
+ setIsConsentLoading(false);
if (error) {
await handleError(error);
@@ -113,7 +117,7 @@ const Consent = () => {
window.location.replace(consentData.redirectUri);
}}
/>
-
+
{!showTerms && (
diff --git a/packages/experience/src/pages/Continue/IdentifierProfileForm/index.tsx b/packages/experience/src/pages/Continue/IdentifierProfileForm/index.tsx
index 19e3b9448..07f673570 100644
--- a/packages/experience/src/pages/Continue/IdentifierProfileForm/index.tsx
+++ b/packages/experience/src/pages/Continue/IdentifierProfileForm/index.tsx
@@ -43,7 +43,7 @@ const IdentifierProfileForm = ({
const {
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
defaultValues: {
@@ -64,7 +64,7 @@ const IdentifierProfileForm = ({
async (event?: React.FormEvent) => {
clearErrorMessage?.();
- void handleSubmit(async ({ identifier: { type, value } }) => {
+ await handleSubmit(async ({ identifier: { type, value } }) => {
if (!type) {
return;
}
@@ -115,7 +115,7 @@ const IdentifierProfileForm = ({
{errorMessage && {errorMessage}}
-
+
diff --git a/packages/experience/src/pages/ForgotPassword/ForgotPasswordForm/index.tsx b/packages/experience/src/pages/ForgotPassword/ForgotPasswordForm/index.tsx
index 381bf12bd..e1db29743 100644
--- a/packages/experience/src/pages/ForgotPassword/ForgotPasswordForm/index.tsx
+++ b/packages/experience/src/pages/ForgotPassword/ForgotPasswordForm/index.tsx
@@ -42,12 +42,13 @@ const ForgotPasswordForm = ({
UserFlow.ForgotPassword
);
- const { setForgotPasswordIdentifierInputValue } = useContext(UserInteractionContext);
+ const { setForgotPasswordIdentifierInputValue, setIdentifierInputValue } =
+ useContext(UserInteractionContext);
const {
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
defaultValues: {
@@ -76,10 +77,19 @@ const ForgotPasswordForm = ({
// Cache or update the forgot password identifier input value
setForgotPasswordIdentifierInputValue({ type, value });
+ // Set current identifier input value for code verification
+ setIdentifierInputValue({ type, value });
+
await onSubmit({ identifier: type, value });
})(event);
},
- [clearErrorMessage, handleSubmit, onSubmit, setForgotPasswordIdentifierInputValue]
+ [
+ clearErrorMessage,
+ handleSubmit,
+ onSubmit,
+ setForgotPasswordIdentifierInputValue,
+ setIdentifierInputValue,
+ ]
);
return (
@@ -122,7 +132,7 @@ const ForgotPasswordForm = ({
{errorMessage && {errorMessage}}
-
+
diff --git a/packages/experience/src/pages/MfaBinding/BackupCodeBinding/index.tsx b/packages/experience/src/pages/MfaBinding/BackupCodeBinding/index.tsx
index 3d113036c..63f65d6c2 100644
--- a/packages/experience/src/pages/MfaBinding/BackupCodeBinding/index.tsx
+++ b/packages/experience/src/pages/MfaBinding/BackupCodeBinding/index.tsx
@@ -1,5 +1,6 @@
import { MfaFactor } from '@logto/schemas';
import { t } from 'i18next';
+import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { validate } from 'superstruct';
@@ -18,6 +19,7 @@ import * as styles from './index.module.scss';
const BackupCodeBinding = () => {
const { copyText, downloadText } = useTextHandler();
const sendMfaPayload = useSendMfaPayload();
+ const [isSubmitting, setIsSubmitting] = useState(false);
const { state } = useLocation();
const [, backupCodeBindingState] = validate(state, backupCodeBindingStateGuard);
@@ -46,7 +48,7 @@ const BackupCodeBinding = () => {
{
- void sendMfaPayload({
+ isLoading={isSubmitting}
+ onClick={async () => {
+ setIsSubmitting(true);
+ await sendMfaPayload({
flow: UserMfaFlow.MfaBinding,
payload: { type: MfaFactor.BackupCode },
});
+ setIsSubmitting(false);
}}
/>
diff --git a/packages/experience/src/pages/MfaBinding/WebAuthnBinding/index.tsx b/packages/experience/src/pages/MfaBinding/WebAuthnBinding/index.tsx
index 1678b42b8..9eca7bc98 100644
--- a/packages/experience/src/pages/MfaBinding/WebAuthnBinding/index.tsx
+++ b/packages/experience/src/pages/MfaBinding/WebAuthnBinding/index.tsx
@@ -1,4 +1,5 @@
import { conditional } from '@silverhand/essentials';
+import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { validate } from 'superstruct';
@@ -19,6 +20,7 @@ const WebAuthnBinding = () => {
const [, webAuthnState] = validate(state, webAuthnStateGuard);
const handleWebAuthn = useWebAuthnOperation();
const skipMfa = useSkipMfa();
+ const [isCreatingPasskey, setIsCreatingPasskey] = useState(false);
if (!webAuthnState) {
return ;
@@ -38,8 +40,11 @@ const WebAuthnBinding = () => {
>
{
- void handleWebAuthn(options);
+ isLoading={isCreatingPasskey}
+ onClick={async () => {
+ setIsCreatingPasskey(true);
+ await handleWebAuthn(options);
+ setIsCreatingPasskey(false);
}}
/>
{
const flowState = useMfaFlowState();
const sendMfaPayload = useSendMfaPayload();
- const { register, handleSubmit } = useForm({ defaultValues: { code: '' } });
+ const {
+ register,
+ handleSubmit,
+ formState: { isSubmitting },
+ } = useForm({ defaultValues: { code: '' } });
const onSubmitHandler = useCallback(
- (event?: FormEvent) => {
- void handleSubmit(async ({ code }) => {
- void sendMfaPayload({
+ async (event?: FormEvent) => {
+ await handleSubmit(async ({ code }) => {
+ await sendMfaPayload({
flow: UserMfaFlow.MfaVerification,
payload: { type: MfaFactor.BackupCode, code },
});
@@ -53,7 +57,7 @@ const BackupCodeVerification = () => {
className={styles.backupCodeInput}
{...register('code')}
/>
-
+
{
const { state } = useLocation();
const [, webAuthnState] = validate(state, webAuthnStateGuard);
const handleWebAuthn = useWebAuthnOperation();
+ const [isVerifying, setIsVerifying] = useState(false);
if (!webAuthnState) {
return ;
@@ -37,8 +39,11 @@ const WebAuthnVerification = () => {
{
- void handleWebAuthn(options);
+ isLoading={isVerifying}
+ onClick={async () => {
+ setIsVerifying(true);
+ await handleWebAuthn(options);
+ setIsVerifying(false);
}}
/>
diff --git a/packages/experience/src/pages/Register/IdentifierRegisterForm/index.tsx b/packages/experience/src/pages/Register/IdentifierRegisterForm/index.tsx
index cc198194b..3d03e1b18 100644
--- a/packages/experience/src/pages/Register/IdentifierRegisterForm/index.tsx
+++ b/packages/experience/src/pages/Register/IdentifierRegisterForm/index.tsx
@@ -40,7 +40,7 @@ const IdentifierRegisterForm = ({ className, autoFocus, signUpMethods }: Props)
const {
watch,
handleSubmit,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
control,
} = useForm({
reValidateMode: 'onBlur',
@@ -154,6 +154,7 @@ const IdentifierRegisterForm = ({ className, autoFocus, signUpMethods }: Props)
title={showSingleSignOnForm ? 'action.single_sign_on' : 'action.create_account'}
icon={showSingleSignOnForm ? : undefined}
htmlType="submit"
+ isLoading={isSubmitting}
/>
diff --git a/packages/experience/src/pages/SignIn/IdentifierSignInForm/index.tsx b/packages/experience/src/pages/SignIn/IdentifierSignInForm/index.tsx
index 39e2c2596..5049b7f17 100644
--- a/packages/experience/src/pages/SignIn/IdentifierSignInForm/index.tsx
+++ b/packages/experience/src/pages/SignIn/IdentifierSignInForm/index.tsx
@@ -44,7 +44,7 @@ const IdentifierSignInForm = ({ className, autoFocus, signInMethods }: Props) =>
watch,
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
});
@@ -153,6 +153,7 @@ const IdentifierSignInForm = ({ className, autoFocus, signInMethods }: Props) =>
title={showSingleSignOnForm ? 'action.single_sign_on' : 'action.sign_in'}
icon={showSingleSignOnForm ? : undefined}
htmlType="submit"
+ isLoading={isSubmitting}
/>
diff --git a/packages/experience/src/pages/SignIn/PasswordSignInForm/index.tsx b/packages/experience/src/pages/SignIn/PasswordSignInForm/index.tsx
index 3ce300d5e..47c91e213 100644
--- a/packages/experience/src/pages/SignIn/PasswordSignInForm/index.tsx
+++ b/packages/experience/src/pages/SignIn/PasswordSignInForm/index.tsx
@@ -45,7 +45,7 @@ const PasswordSignInForm = ({ className, autoFocus, signInMethods }: Props) => {
register,
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
defaultValues: {
@@ -174,6 +174,7 @@ const PasswordSignInForm = ({ className, autoFocus, signInMethods }: Props) => {
title={showSingleSignOnForm ? 'action.single_sign_on' : 'action.sign_in'}
icon={showSingleSignOnForm ? : undefined}
htmlType="submit"
+ isLoading={isSubmitting}
/>
diff --git a/packages/experience/src/pages/SignInPassword/PasswordForm/index.tsx b/packages/experience/src/pages/SignInPassword/PasswordForm/index.tsx
index 2deb89de7..4b6951d43 100644
--- a/packages/experience/src/pages/SignInPassword/PasswordForm/index.tsx
+++ b/packages/experience/src/pages/SignInPassword/PasswordForm/index.tsx
@@ -47,7 +47,7 @@ const PasswordForm = ({
register,
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
defaultValues: {
@@ -69,7 +69,7 @@ const PasswordForm = ({
async (event?: React.FormEvent) => {
clearErrorMessage();
- void handleSubmit(async ({ identifier: { type, value }, password }) => {
+ await handleSubmit(async ({ identifier: { type, value }, password }) => {
if (!type) {
return;
}
@@ -114,7 +114,7 @@ const PasswordForm = ({
)}
-
+
{identifier !== SignInIdentifier.Username && isVerificationCodeEnabled && (
diff --git a/packages/experience/src/pages/SingleSignOnEmail/index.tsx b/packages/experience/src/pages/SingleSignOnEmail/index.tsx
index 86437fe4d..3abe821ff 100644
--- a/packages/experience/src/pages/SingleSignOnEmail/index.tsx
+++ b/packages/experience/src/pages/SingleSignOnEmail/index.tsx
@@ -26,7 +26,7 @@ const SingleSignOnEmail = () => {
const {
handleSubmit,
control,
- formState: { errors, isValid },
+ formState: { errors, isValid, isSubmitting },
} = useForm({
reValidateMode: 'onBlur',
});
@@ -82,7 +82,12 @@ const SingleSignOnEmail = () => {
{errorMessage && {errorMessage}}
- } />
+ }
+ isLoading={isSubmitting}
+ />
diff --git a/packages/experience/src/scss/_colors.scss b/packages/experience/src/scss/_colors.scss
index b1d1e4b00..2952cb391 100644
--- a/packages/experience/src/scss/_colors.scss
+++ b/packages/experience/src/scss/_colors.scss
@@ -38,6 +38,7 @@
--color-brand-30: #4300da;
--color-brand-40: #5d34f2;
--color-brand-50: #7958ff;
+ --color-brand-70: #af9eff;
--color-alert-60: #ca8000;
--color-alert-70: #eb9918;