diff --git a/packages/sdks/react-sdk/src/components/Descope.tsx b/packages/sdks/react-sdk/src/components/Descope.tsx index 4f93c6189..48ba76500 100644 --- a/packages/sdks/react-sdk/src/components/Descope.tsx +++ b/packages/sdks/react-sdk/src/components/Descope.tsx @@ -56,6 +56,7 @@ const DescopeWC = lazy(async () => { styleId, autoFocus, validateOnBlur, + autoClearError, restartOnError, storeLastAuthenticatedUser, }) => ( @@ -75,6 +76,7 @@ const DescopeWC = lazy(async () => { redirect-url={redirectUrl} auto-focus={autoFocus} validate-on-blur={validateOnBlur} + auto-clear-error={autoClearError} restart-on-error={restartOnError} store-last-authenticated-user={storeLastAuthenticatedUser} /> @@ -100,6 +102,7 @@ const Descope = React.forwardRef( redirectUrl, autoFocus, validateOnBlur, + autoClearError, restartOnError, errorTransformer, styleId, @@ -223,6 +226,7 @@ const Descope = React.forwardRef( autoFocus={autoFocus} styleId={styleId} validateOnBlur={validateOnBlur} + autp-clear-erro={autoClearError} restartOnError={restartOnError} storeLastAuthenticatedUser={storeLastAuthenticatedUser} keepLastAuthenticatedUserAfterLogout={ diff --git a/packages/sdks/react-sdk/src/types.ts b/packages/sdks/react-sdk/src/types.ts index 5e9e431b9..099cb5081 100644 --- a/packages/sdks/react-sdk/src/types.ts +++ b/packages/sdks/react-sdk/src/types.ts @@ -117,6 +117,7 @@ export type DescopeProps = { locale?: string; autoFocus?: AutoFocusOptions; validateOnBlur?: boolean; + autoClearError?: boolean; restartOnError?: boolean; debug?: boolean; telemetryKey?: string; diff --git a/packages/sdks/web-component/README.md b/packages/sdks/web-component/README.md index f93bd35b2..4a27fbc6f 100644 --- a/packages/sdks/web-component/README.md +++ b/packages/sdks/web-component/README.md @@ -78,15 +78,13 @@ NOTE: This package is a part of a monorepo. so if you make changes in a dependen | debug | **"true"** - Enable debugger
**"false"** - Disable debugger | **"false"** | | preview | **"true"** - Run flow in a preview mode
**"false"** - Do run flow in a preview mode | **"false"** | | auto-focus | **"true"** - Automatically focus on the first input of each screen
**"false"** - Do not automatically focus on screen's inputs
**"skipFirstScreen"** - Automatically focus on the first input of each screen, except first screen | **"true"** | - -| validate-on-blur | **"true"** - Triggers the input validation upon blur in addition to the validation on submit
**"false"** - Do not triggers validation upon blur
| **"false"** | - -| restart-on-error | **"true"** - In case of flow version mismatch, will restart the flow if the components version was not changed
**"false"** - Do not restart the flow automatically
| **"false"** | - +| validate-on-blur | **"true"** - Triggers the input validation upon blur in addition to the validation on submit
**"false"** - Do not triggers validation upon blur
| **"false"** | +| auto-clear-error | **"true"** - Clears form's error message on interaction
**"false"** - Does not clear form error message
| **"false"** | +| restart-on-error | **"true"** - In case of flow version mismatch, will restart the flow if the components version was not changed
**"false"** - Do not restart the flow automatically
| **"false"** | | storage-prefix | **String** - A prefix to add to the key of the local storage when persisting tokens | **""** | | store-last-authenticated-user | **"true"** - Stores last-authenticated user details in local storage when flow is completed
**"false"** - Do not store last-auth user details. Disabling this flag may cause last-authenticated user features to not function properly | **"true"** | | keep-last-authenticated-user-after-logout | **"true"** - Do not clear the last authenticated user details from the browser storage after logout
**"false"** - Clear the last authenticated user details from the browser storage after logout | **"false"** | -| style-id | **"String"** - Set a specific style to load rather then the default style | **""** | +| style-id | **"String"** - Set a specific style to load rather then the default style | **""** | ## Optional Properties diff --git a/packages/sdks/web-component/src/app/index.html b/packages/sdks/web-component/src/app/index.html index 7413c1734..051a0a385 100644 --- a/packages/sdks/web-component/src/app/index.html +++ b/packages/sdks/web-component/src/app/index.html @@ -45,6 +45,7 @@ locale="" debug="true" validate-on-blur="false" + auto-clear-error="false" keep-last-authenticated-user-after-logout="true" >
Loading ...
diff --git a/packages/sdks/web-component/src/lib/descope-wc/BaseDescopeWc.ts b/packages/sdks/web-component/src/lib/descope-wc/BaseDescopeWc.ts index 4499338d4..1e8125880 100644 --- a/packages/sdks/web-component/src/lib/descope-wc/BaseDescopeWc.ts +++ b/packages/sdks/web-component/src/lib/descope-wc/BaseDescopeWc.ts @@ -59,6 +59,7 @@ class BaseDescopeWc extends BaseClass { 'store-last-authenticated-user', 'keep-last-authenticated-user-after-logout', 'validate-on-blur', + 'auto-clear-error', 'style-id', ]; } @@ -174,6 +175,10 @@ class BaseDescopeWc extends BaseClass { return this.getAttribute('validate-on-blur') === 'true'; } + get autoClearError() { + return this.getAttribute('auto-clear-error') === 'true'; + } + get storeLastAuthenticatedUser() { const res = this.getAttribute('store-last-authenticated-user') ?? 'true'; return res === 'true'; @@ -219,6 +224,7 @@ class BaseDescopeWc extends BaseClass { 'form', 'client', 'validate-on-blur', + 'auto-clear-error', 'style-id', ]; diff --git a/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts b/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts index 2fb072951..3a0cdebbc 100644 --- a/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts +++ b/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts @@ -867,6 +867,7 @@ class DescopeWc extends BaseDescopeWc { samlIdpResponseRelayState: samlIdpResponse?.relayState, nativeResponseType: nativeResponse?.type, nativePayload: nativeResponse?.payload, + forceUpdate: this.autoClearError && errorText }); }; @@ -1006,8 +1007,6 @@ class DescopeWc extends BaseDescopeWc { this.loggerWrapper, ); - this.#handleErrorMessageClearing(); - // set the default country code based on the locale value we got const { geo } = await this.getExecutionContext(); setPhoneAutoDetectDefaultCode(clone, geo); @@ -1041,6 +1040,10 @@ class DescopeWc extends BaseDescopeWc { // we need to wait for all components to render before we can set its value updateScreenFromScreenState(this.rootElement, screenState); + + if (this.autoClearError && screenState.errorText) { + this.#handleErrorMessageClearing(); + } }); this.#hydrate(next); @@ -1296,24 +1299,20 @@ class DescopeWc extends BaseDescopeWc { } #handleErrorMessageClearing() { - // we need to wait for the component is populated with the error message - setTimeout(() => { - const errorMsgs = this.shadowRoot.querySelectorAll( - '[data-type="error-message"][data-auto-clear="true"]', - ); - if (errorMsgs.length) { - const onErrorMsgClear = () => { - Array.from(errorMsgs).forEach((errorMsg) => { - // eslint-disable-next-line no-param-reassign - errorMsg.innerHTML = ''; - this.removeEventListener('click', onErrorMsgClear); - this.removeEventListener('keypress', onErrorMsgClear); - }); - }; - this.addEventListener('click', onErrorMsgClear); - this.addEventListener('keypress', onErrorMsgClear); - } - }); + const errorMsgs = this.shadowRoot.querySelectorAll( + '[data-type="error-message"]', + ); + + if (errorMsgs.length) { + const onErrorMsgClear = () => { + Array.from(errorMsgs).forEach((errorMsg) => { + // eslint-disable-next-line no-param-reassign + errorMsg.innerHTML = ''; + this.removeEventListener('keydown', onErrorMsgClear); + }); + }; + this.addEventListener('keydown', onErrorMsgClear); + } } } diff --git a/packages/sdks/web-component/src/lib/helpers/state.ts b/packages/sdks/web-component/src/lib/helpers/state.ts index 5fc05eba0..9b0f26925 100644 --- a/packages/sdks/web-component/src/lib/helpers/state.ts +++ b/packages/sdks/web-component/src/lib/helpers/state.ts @@ -69,7 +69,7 @@ class State { typeof newState === 'function' ? newState(this.#state) : newState; const nextState = { ...this.#state, ...internalNewState }; - if (!this.#updateOnlyOnChange || !compareObjects(this.#state, nextState)) { + if (!this.#updateOnlyOnChange || !compareObjects(this.#state, nextState) || nextState.forceUpdate) { const prevState = this.#state; this.#state = nextState; Object.freeze(this.#state); diff --git a/packages/sdks/web-component/src/lib/types.ts b/packages/sdks/web-component/src/lib/types.ts index f151b68ed..afc1d2a20 100644 --- a/packages/sdks/web-component/src/lib/types.ts +++ b/packages/sdks/web-component/src/lib/types.ts @@ -87,6 +87,7 @@ export type FlowState = { samlIdpResponseRelayState: string; nativeResponseType: string; nativePayload: Record; + forceUpdate?: string; } & SSOQueryParams; export type StepState = {