diff --git a/dapp/src/DApp.tsx b/dapp/src/DApp.tsx index 31255b53d..587d248ef 100644 --- a/dapp/src/DApp.tsx +++ b/dapp/src/DApp.tsx @@ -10,7 +10,7 @@ import GlobalStyles from "./components/GlobalStyles" import { DocsDrawerContextProvider, SidebarContextProvider, - WalletConnectionErrorContextProvider, + WalletConnectionAlertContextProvider, } from "./contexts" import { useInitApp } from "./hooks" import { router } from "./router" @@ -67,11 +67,11 @@ function DAppProviders() { - + - + diff --git a/dapp/src/components/ConnectWalletModal/ConnectWalletAlert.tsx b/dapp/src/components/ConnectWalletModal/ConnectWalletAlert.tsx new file mode 100644 index 000000000..70da999ff --- /dev/null +++ b/dapp/src/components/ConnectWalletModal/ConnectWalletAlert.tsx @@ -0,0 +1,93 @@ +import React from "react" +import { Box, Link, VStack } from "@chakra-ui/react" +import { AnimatePresence, Variants, motion } from "framer-motion" +import { EXTERNAL_HREF } from "#/constants" +import { + Alert, + AlertDescription, + AlertTitle, + AlertIcon, + AlertProps, +} from "../shared/Alert" + +export enum ConnectionAlert { + Rejected = "REJECTED", + NotSupported = "NOT_SUPPORTED", + NetworkMismatch = "NETWORK_MISMATCH", + InvalidSIWWSignature = "INVALID_SIWW_SIGNATURE", + Default = "DEFAULT", +} + +const CONNECTION_ALERTS = { + [ConnectionAlert.Rejected]: { + title: "Wallet connection rejected.", + description: "If you encountered an error, please try again.", + }, + [ConnectionAlert.NotSupported]: { + title: "Not supported.", + description: + "Only Native SegWit, Nested SegWit or Legacy addresses supported at this time. Please try a different address or another wallet.", + }, + [ConnectionAlert.NetworkMismatch]: { + title: "Error!", + description: + "Incorrect network detected in your wallet. Please choose proper network and try again.", + }, + [ConnectionAlert.Default]: { + title: "Wallet connection error. Please try again.", + description: ( + + If the problem persists, contact{" "} + + Acre support + + + ), + }, + [ConnectionAlert.InvalidSIWWSignature]: { + title: "Invalid Sign In With Wallet signature", + description: "We encountered an error. Please try again.", + }, +} + +const collapseVariants: Variants = { + collapsed: { height: 0 }, + expanded: { height: "auto" }, +} + +type ConnectWalletAlertProps = AlertProps & { type?: ConnectionAlert } + +export default function ConnectWalletAlert(props: ConnectWalletAlertProps) { + const { type, ...restProps } = props + + const data = type ? CONNECTION_ALERTS[type] : undefined + + return ( + + {data && ( + + + + + {data.title} + {data.description} + + + + )} + + ) +} diff --git a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx index 0747fdc8e..e3250bea3 100644 --- a/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx +++ b/dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx @@ -1,12 +1,12 @@ import React, { useCallback, useEffect, useRef, useState } from "react" -import { CONNECTION_ERRORS, ONE_SEC_IN_MILLISECONDS } from "#/constants" +import { ONE_SEC_IN_MILLISECONDS } from "#/constants" import { useAppDispatch, useIsEmbed, useModal, useSignMessageAndCreateSession, useWallet, - useWalletConnectionError, + useWalletConnectionAlert, } from "#/hooks" import { setIsSignedMessage } from "#/store/wallet" import { OrangeKitConnector, OrangeKitError, OnSuccessCallback } from "#/types" @@ -28,6 +28,7 @@ import ArrivingSoonTooltip from "../ArrivingSoonTooltip" import { TextLg, TextMd } from "../shared/Typography" import ConnectWalletStatusLabel from "./ConnectWalletStatusLabel" import Spinner from "../shared/Spinner" +import { ConnectionAlert } from "./ConnectWalletAlert" type ConnectWalletButtonProps = { label: string @@ -66,15 +67,15 @@ export default function ConnectWalletButton({ } = useWallet() const { signMessageStatus, resetMessageStatus, signMessageAndCreateSession } = useSignMessageAndCreateSession() - const { connectionError, setConnectionError, resetConnectionError } = - useWalletConnectionError() + const { type, setConnectionAlert, resetConnectionAlert } = + useWalletConnectionAlert() const { closeModal } = useModal() const dispatch = useAppDispatch() const isMounted = useRef(false) const [isLoading, setIsLoading] = useState(false) - const hasConnectionError = connectionError || connectionStatus === "error" + const hasConnectionError = type || connectionStatus === "error" const hasSignMessageErrorStatus = signMessageStatus === "error" const shouldShowStatuses = isSelected && !hasConnectionError const shouldShowRetryButton = address && hasSignMessageErrorStatus @@ -99,14 +100,14 @@ export default function ConnectWalletButton({ onDisconnect() console.error("Failed to sign siww message", error) - setConnectionError(CONNECTION_ERRORS.INVALID_SIWW_SIGNATURE) + setConnectionAlert(ConnectionAlert.InvalidSIWWSignature) } }, [ signMessageAndCreateSession, onSuccessSignMessage, onDisconnect, - setConnectionError, + setConnectionAlert, ], ) @@ -129,14 +130,14 @@ export default function ConnectWalletButton({ }, onError: (error: OrangeKitError) => { const errorData = orangeKit.parseOrangeKitConnectionError(error) - setConnectionError(errorData) + setConnectionAlert(errorData) }, }) }, [ onConnect, connector, onSuccessConnection, - setConnectionError, + setConnectionAlert, isReconnecting, ]) @@ -159,7 +160,7 @@ export default function ConnectWalletButton({ if (shouldShowStatuses) return if (!isReconnecting) onDisconnect() - resetConnectionError() + resetConnectionAlert() resetMessageStatus() const isInstalled = orangeKit.isWalletInstalled(connector) diff --git a/dapp/src/components/ConnectWalletModal/ConnectWalletErrorAlert.tsx b/dapp/src/components/ConnectWalletModal/ConnectWalletErrorAlert.tsx deleted file mode 100644 index 2e97b59ea..000000000 --- a/dapp/src/components/ConnectWalletModal/ConnectWalletErrorAlert.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from "react" -import { Box, VStack } from "@chakra-ui/react" -import { AnimatePresence, Variants, motion } from "framer-motion" -import { ConnectionErrorData } from "#/types" -import { - Alert, - AlertDescription, - AlertTitle, - AlertIcon, - AlertProps, -} from "../shared/Alert" - -type ConnectWalletErrorAlertProps = AlertProps & Partial - -const collapseVariants: Variants = { - collapsed: { height: 0 }, - expanded: { height: "auto" }, -} - -export default function ConnectWalletErrorAlert( - props: ConnectWalletErrorAlertProps, -) { - const { title, description, ...restProps } = props - - const shouldRender = !!(title && description) - - return ( - - {shouldRender && ( - - - - - {title} - {description} - - - - )} - - ) -} diff --git a/dapp/src/components/ConnectWalletModal/index.tsx b/dapp/src/components/ConnectWalletModal/index.tsx index 66816f2be..1653d1e11 100644 --- a/dapp/src/components/ConnectWalletModal/index.tsx +++ b/dapp/src/components/ConnectWalletModal/index.tsx @@ -5,13 +5,13 @@ import { useIsEmbed, useIsSignedMessage, useWallet, - useWalletConnectionError, + useWalletConnectionAlert, } from "#/hooks" import { OrangeKitConnector, BaseModalProps, OnSuccessCallback } from "#/types" import { wallets } from "#/constants" import withBaseModal from "../ModalRoot/withBaseModal" import ConnectWalletButton from "./ConnectWalletButton" -import ConnectWalletErrorAlert from "./ConnectWalletErrorAlert" +import ConnectWalletAlert from "./ConnectWalletAlert" export function ConnectWalletModalBase({ onSuccess, @@ -30,7 +30,7 @@ export function ConnectWalletModalBase({ })) const [selectedConnectorId, setSelectedConnectorId] = useState() - const { connectionError, resetConnectionError } = useWalletConnectionError() + const { type, status, resetConnectionAlert } = useWalletConnectionAlert() const isSignedMessage = useIsSignedMessage() const handleButtonOnClick = (connector: OrangeKitConnector) => { @@ -48,7 +48,7 @@ export function ConnectWalletModalBase({ {withCloseButton && ( { - resetConnectionError() + resetConnectionAlert() if (!isSignedMessage) { onDisconnect() @@ -59,7 +59,7 @@ export function ConnectWalletModalBase({ {`Select your ${isEmbed ? "account" : "wallet"}`} - + {enabledConnectors.map((connector) => ( = { - REJECTED: { - title: "Wallet connection rejected.", - description: "If you encountered an error, please try again.", - }, - NOT_SUPPORTED: { - title: "Not supported.", - description: - "Only Native SegWit, Nested SegWit or Legacy addresses supported at this time. Please try a different address or another wallet.", - }, - NETWORK_MISMATCH: { - title: "Error!", - description: - "Incorrect network detected in your wallet. Please choose proper network and try again.", - }, - DEFAULT: { - title: "Something went wrong...", - description: "We encountered an error. Please try again.", - }, - INVALID_SIWW_SIGNATURE: { - title: "Invalid Sign In With Wallet signature", - description: "We encountered an error. Please try again.", - }, -} +import { ACTION_FLOW_TYPES } from "#/types" export const TOKEN_FORM_ERRORS = { REQUIRED: "Please enter an amount.", diff --git a/dapp/src/contexts/WalletConnectionAlertContext.tsx b/dapp/src/contexts/WalletConnectionAlertContext.tsx new file mode 100644 index 000000000..7a62ac050 --- /dev/null +++ b/dapp/src/contexts/WalletConnectionAlertContext.tsx @@ -0,0 +1,54 @@ +import { ConnectionAlert } from "#/components/ConnectWalletModal/ConnectWalletAlert" +import { AlertStatus } from "@chakra-ui/react" +import React, { createContext, useCallback, useMemo, useState } from "react" + +type WalletConnectionAlertContextValue = { + type?: ConnectionAlert + status: AlertStatus + setConnectionAlert: (type: ConnectionAlert, status?: AlertStatus) => void + resetConnectionAlert: () => void +} + +export const WalletConnectionAlertContext = + createContext( + {} as WalletConnectionAlertContextValue, + ) + +export function WalletConnectionAlertContextProvider({ + children, +}: { + children: React.ReactNode +}): React.ReactElement { + const [type, setType] = useState() + const [status, setStatus] = useState("error") + + const resetConnectionAlert = useCallback(() => { + setType(undefined) + setStatus("error") + }, [setType]) + + const setConnectionAlert = useCallback( + (connectionAlert: ConnectionAlert, alertStatus: AlertStatus = "error") => { + setType(connectionAlert) + setStatus(alertStatus) + }, + [setType], + ) + + const contextValue: WalletConnectionAlertContextValue = + useMemo( + () => ({ + type, + status, + setConnectionAlert, + resetConnectionAlert, + }), + [resetConnectionAlert, setConnectionAlert, status, type], + ) + + return ( + + {children} + + ) +} diff --git a/dapp/src/contexts/WalletConnectionErrorContext.tsx b/dapp/src/contexts/WalletConnectionErrorContext.tsx deleted file mode 100644 index 23838bac2..000000000 --- a/dapp/src/contexts/WalletConnectionErrorContext.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { ConnectionErrorData } from "#/types" -import React, { createContext, useCallback, useMemo, useState } from "react" - -type WalletConnectionErrorContextValue = { - connectionError: ConnectionErrorData | undefined - setConnectionError: (data: ConnectionErrorData) => void - resetConnectionError: () => void -} - -export const WalletConnectionErrorContext = - createContext( - {} as WalletConnectionErrorContextValue, - ) - -export function WalletConnectionErrorContextProvider({ - children, -}: { - children: React.ReactNode -}): React.ReactElement { - const [connectionError, setConnectionError] = useState() - - const resetConnectionError = useCallback( - () => setConnectionError(undefined), - [setConnectionError], - ) - - const contextValue: WalletConnectionErrorContextValue = - useMemo( - () => ({ - connectionError, - setConnectionError, - resetConnectionError, - }), - [connectionError, resetConnectionError, setConnectionError], - ) - - return ( - - {children} - - ) -} diff --git a/dapp/src/contexts/index.tsx b/dapp/src/contexts/index.tsx index 5781528dd..658feecbd 100644 --- a/dapp/src/contexts/index.tsx +++ b/dapp/src/contexts/index.tsx @@ -2,4 +2,4 @@ export * from "./DocsDrawerContext" export * from "./SidebarContext" export * from "./StakeFlowContext" export * from "./PaginationContext" -export * from "./WalletConnectionErrorContext" +export * from "./WalletConnectionAlertContext" diff --git a/dapp/src/hooks/index.ts b/dapp/src/hooks/index.ts index 28bc42703..c0ebd7792 100644 --- a/dapp/src/hooks/index.ts +++ b/dapp/src/hooks/index.ts @@ -20,7 +20,7 @@ export * from "./useTransactionModal" export * from "./useVerifyDepositAddress" export { default as useStatistics } from "./useStatistics" export * from "./useDisconnectWallet" -export * from "./useWalletConnectionError" +export { default as useWalletConnectionAlert } from "./useWalletConnectionAlert" export { default as useInvalidateQueries } from "./useInvalidateQueries" export { default as useResetWalletState } from "./useResetWalletState" export { default as useMobileMode } from "./useMobileMode" diff --git a/dapp/src/hooks/useWalletConnectionAlert.ts b/dapp/src/hooks/useWalletConnectionAlert.ts new file mode 100644 index 000000000..bab475294 --- /dev/null +++ b/dapp/src/hooks/useWalletConnectionAlert.ts @@ -0,0 +1,6 @@ +import { WalletConnectionAlertContext } from "#/contexts" +import { useContext } from "react" + +export default function useWalletConnectionAlert() { + return useContext(WalletConnectionAlertContext) +} diff --git a/dapp/src/hooks/useWalletConnectionError.ts b/dapp/src/hooks/useWalletConnectionError.ts deleted file mode 100644 index 55fae3a56..000000000 --- a/dapp/src/hooks/useWalletConnectionError.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { WalletConnectionErrorContext } from "#/contexts" -import { useContext } from "react" - -export function useWalletConnectionError() { - return useContext(WalletConnectionErrorContext) -} diff --git a/dapp/src/types/error.ts b/dapp/src/types/error.ts deleted file mode 100644 index 975af0f65..000000000 --- a/dapp/src/types/error.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type ConnectionErrorData = { - title: string - description: string -} diff --git a/dapp/src/types/index.ts b/dapp/src/types/index.ts index 13bdda39c..aa1e0e3b0 100644 --- a/dapp/src/types/index.ts +++ b/dapp/src/types/index.ts @@ -10,7 +10,6 @@ export * from "./fee" export * from "./modal" export * from "./form" export * from "./eip1193" -export * from "./error" export * from "./status" export * from "./orangekit" export * from "./ledgerLive" diff --git a/dapp/src/utils/orangekit/index.ts b/dapp/src/utils/orangekit/index.ts index 18f355df4..973bcbf19 100644 --- a/dapp/src/utils/orangekit/index.ts +++ b/dapp/src/utils/orangekit/index.ts @@ -1,19 +1,12 @@ -import { - ACRE_SESSION_EXPIRATION_TIME, - CONNECTION_ERRORS, - wallets, -} from "#/constants" -import { - ConnectionErrorData, - OrangeKitError, - OrangeKitConnector, -} from "#/types" +import { ACRE_SESSION_EXPIRATION_TIME, wallets } from "#/constants" +import { OrangeKitError, OrangeKitConnector } from "#/types" import { isUnsupportedBitcoinAddressError, isWalletNetworkDoesNotMatchProviderChainError, } from "@orangekit/react" import { Connector } from "wagmi" import { SignInWithWalletMessage } from "@orangekit/sign-in-with-wallet" +import { ConnectionAlert } from "#/components/ConnectWalletModal/ConnectWalletAlert" import { getExpirationDate } from "../time" import { getOrangeKitLedgerLiveConnector } from "./ledger-live" @@ -71,22 +64,22 @@ const typeConversionToConnector = (connector?: OrangeKitConnector): Connector => const parseOrangeKitConnectionError = ( error: OrangeKitError, -): ConnectionErrorData => { +): ConnectionAlert => { const { cause } = error if (isWalletConnectionRejectedError(cause)) { - return CONNECTION_ERRORS.REJECTED + return ConnectionAlert.Rejected } if (isUnsupportedBitcoinAddressError(cause)) { - return CONNECTION_ERRORS.NOT_SUPPORTED + return ConnectionAlert.NotSupported } if (isWalletNetworkDoesNotMatchProviderChainError(cause)) { - return CONNECTION_ERRORS.NETWORK_MISMATCH + return ConnectionAlert.NetworkMismatch } - return CONNECTION_ERRORS.DEFAULT + return ConnectionAlert.Default } async function verifySignInWithWalletMessage(