diff --git a/packages/modal/src/ui/components/Loader/Loader.tsx b/packages/modal/src/ui/components/Loader/Loader.tsx
index 063175ec4..b5ae1b90d 100644
--- a/packages/modal/src/ui/components/Loader/Loader.tsx
+++ b/packages/modal/src/ui/components/Loader/Loader.tsx
@@ -1,4 +1,4 @@
-import { WALLET_CONNECTOR_TYPE } from "@web3auth/no-modal";
+import { log, WALLET_CONNECTOR_TYPE } from "@web3auth/no-modal";
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -6,7 +6,7 @@ import { MODAL_STATUS } from "../../interfaces";
import i18n from "../../localeImport";
import Image from "../Image";
import SpinnerLoader from "../SpinnerLoader";
-import { AuthorizingStatusType, ConnectedStatusType, ConnectingStatusType, ErroredStatusType, LoaderProps } from "./Loader.type";
+import { AuthorizingStatusType, BlockedStatusType, ConnectedStatusType, ConnectingStatusType, ErroredStatusType, LoaderProps } from "./Loader.type";
/**
* ConnectingStatus component
@@ -83,6 +83,37 @@ function ErroredStatus(props: ErroredStatusType) {
);
}
+function BlockedStatus(props: BlockedStatusType) {
+ const { primaryMessage, secondaryMessage, buttonMessage } = props;
+
+ const handleChangeWallet = () => {
+ // TODO: wire up real action in a follow-up commit
+ log.info("change wallet");
+ };
+
+ return (
+
+
+
{primaryMessage}
+
{secondaryMessage}
+
+
+ );
+}
+
function AuthorizingStatus(props: AuthorizingStatusType) {
const [t] = useTranslation(undefined, { i18n });
const { connector, externalWalletsConfig, handleMobileVerifyConnect } = props;
@@ -213,6 +244,7 @@ function Loader(props: LoaderProps) {
externalWalletsConfig,
handleMobileVerifyConnect,
hideSuccessScreen = false,
+ blockedUserConfig,
onAcceptConsent,
onDeclineConsent,
privacyPolicy,
@@ -255,6 +287,14 @@ function Loader(props: LoaderProps) {
{modalStatus === MODAL_STATUS.ERRORED && }
+ {modalStatus === MODAL_STATUS.BLOCKED && blockedUserConfig && (
+
+ )}
+
{modalStatus === MODAL_STATUS.AUTHORIZING && (
;
@@ -12,6 +12,7 @@ export interface LoaderProps {
isConnectAndSignAuthenticationMode: boolean;
handleMobileVerifyConnect: (params: { connector: WALLET_CONNECTOR_TYPE }) => void;
hideSuccessScreen?: boolean;
+ blockedUserConfig?: BlockedUserConfig;
onAcceptConsent?: () => void | Promise;
onDeclineConsent?: () => void | Promise;
privacyPolicy?: string;
@@ -25,3 +26,5 @@ export type ConnectedStatusType = Pick;
export type ErroredStatusType = Pick;
export type AuthorizingStatusType = Pick;
+
+export type BlockedStatusType = BlockedUserConfig;
diff --git a/packages/modal/src/ui/containers/Root/Root.tsx b/packages/modal/src/ui/containers/Root/Root.tsx
index d6bf756f7..f576b967f 100644
--- a/packages/modal/src/ui/containers/Root/Root.tsx
+++ b/packages/modal/src/ui/containers/Root/Root.tsx
@@ -224,6 +224,7 @@ function RootContent(props: RootProps) {
externalWalletsConfig={modalState.externalWalletsConfig}
handleMobileVerifyConnect={handleMobileVerifyConnect}
hideSuccessScreen={hideSuccessScreen}
+ blockedUserConfig={modalState.blockedUserConfig}
onAcceptConsent={handleAcceptConsent}
onDeclineConsent={handleDeclineConsent}
privacyPolicy={privacyPolicy}
diff --git a/packages/modal/src/ui/containers/Widget/Widget.tsx b/packages/modal/src/ui/containers/Widget/Widget.tsx
index d9cd3c946..b02dc52ff 100644
--- a/packages/modal/src/ui/containers/Widget/Widget.tsx
+++ b/packages/modal/src/ui/containers/Widget/Widget.tsx
@@ -50,6 +50,13 @@ function WidgetContent() {
postLoadingMessage: "",
});
}
+ if (modalState.status === MODAL_STATUS.BLOCKED) {
+ setModalState({
+ ...modalState,
+ modalVisibility: false,
+ externalWalletsVisibility: false,
+ });
+ }
};
const showCloseIcon = useMemo(() => {
@@ -57,6 +64,7 @@ function WidgetContent() {
modalState.status === MODAL_STATUS.INITIALIZED ||
modalState.status === MODAL_STATUS.CONNECTED ||
modalState.status === MODAL_STATUS.ERRORED ||
+ modalState.status === MODAL_STATUS.BLOCKED ||
modalState.status === MODAL_STATUS.AUTHORIZED
);
}, [modalState.status]);
diff --git a/packages/modal/src/ui/interfaces.ts b/packages/modal/src/ui/interfaces.ts
index 43f713cf2..096ecea33 100644
--- a/packages/modal/src/ui/interfaces.ts
+++ b/packages/modal/src/ui/interfaces.ts
@@ -75,6 +75,16 @@ export interface UIConfig extends CoreUIConfig, LoginModalConfig {
*/
hideSuccessScreen?: boolean;
+ /**
+ * Configuration for the blocked user screen shown when a user is blocked by the dapp.
+ * All fields are optional and have defaults.
+ */
+ blockedUserConfig?: {
+ primaryMessage?: string;
+ secondaryMessage?: string;
+ buttonMessage?: string;
+ };
+
connectorListener: SafeEventEmitter;
}
@@ -122,6 +132,7 @@ export const MODAL_STATUS = {
CONNECTED: "connected",
CONNECTING: "connecting",
ERRORED: "errored",
+ BLOCKED: "blocked",
AUTHORIZING: "authorizing",
AUTHORIZED: "authorized",
CONSENT_REQUIRING: "consent_requiring",
@@ -206,6 +217,15 @@ export interface ModalState {
// Config State - set during initialization, rarely changes
socialLoginsConfig: SocialLoginsConfig;
externalWalletsConfig: Record;
+
+ // Blocked user state
+ blockedUserConfig?: BlockedUserConfig;
+}
+
+export interface BlockedUserConfig {
+ primaryMessage: string;
+ secondaryMessage: string;
+ buttonMessage: string;
}
export type SocialLoginEventType = { loginParams: ModalLoginParams };
diff --git a/packages/modal/src/ui/loginModal.tsx b/packages/modal/src/ui/loginModal.tsx
index a324c7518..adebfec3f 100644
--- a/packages/modal/src/ui/loginModal.tsx
+++ b/packages/modal/src/ui/loginModal.tsx
@@ -563,6 +563,18 @@ export class LoginModal {
listener.on(CONNECTOR_EVENTS.ERRORED, (error: Web3AuthError, loginMode: LoginModeType) => {
log.error("error", error, error.message);
if (loginMode === LOGIN_MODE.NO_MODAL) return;
+ if (error.code === 5120) {
+ this.setState({
+ modalVisibility: true,
+ status: MODAL_STATUS.BLOCKED,
+ blockedUserConfig: {
+ primaryMessage: this.uiConfig.blockedUserConfig?.primaryMessage || "You cannot access the site.",
+ secondaryMessage: this.uiConfig.blockedUserConfig?.secondaryMessage || "Access to the site is restricted",
+ buttonMessage: this.uiConfig.blockedUserConfig?.buttonMessage || "Change wallet",
+ },
+ });
+ return;
+ }
if (error.code === 5000) {
if (this.uiConfig.displayErrorsOnModal)
this.setState({
diff --git a/packages/no-modal/src/base/errors/index.ts b/packages/no-modal/src/base/errors/index.ts
index d58507641..441ab6235 100644
--- a/packages/no-modal/src/base/errors/index.ts
+++ b/packages/no-modal/src/base/errors/index.ts
@@ -144,6 +144,7 @@ export class WalletLoginError extends Web3AuthError {
5117: "Unsupported operation",
5118: "useSFAKey flag is enabled but SFA key is not available",
5119: "User not logged in.",
+ 5120: "User is blocked by the application",
};
public constructor(code: number, message?: string, cause?: unknown) {
@@ -193,6 +194,10 @@ export class WalletLoginError extends Web3AuthError {
public static userNotLoggedIn(extraMessage = "", cause?: unknown): IWeb3AuthError {
return WalletLoginError.fromCode(5119, extraMessage, cause);
}
+
+ public static userBlocked(extraMessage = "", cause?: unknown): IWeb3AuthError {
+ return WalletLoginError.fromCode(5120, extraMessage, cause);
+ }
}
export class WalletOperationsError extends Web3AuthError {