Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update alert component for wallet connection #901

Merged
merged 8 commits into from
Dec 3, 2024
Merged
6 changes: 3 additions & 3 deletions dapp/src/DApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import GlobalStyles from "./components/GlobalStyles"
import {
DocsDrawerContextProvider,
SidebarContextProvider,
WalletConnectionErrorContextProvider,
WalletConnectionAlertContextProvider,
} from "./contexts"
import { useInitApp } from "./hooks"
import { router } from "./router"
Expand Down Expand Up @@ -67,11 +67,11 @@ function DAppProviders() {
<AcreSdkProvider>
<DocsDrawerContextProvider>
<SidebarContextProvider>
<WalletConnectionErrorContextProvider>
<WalletConnectionAlertContextProvider>
<ReduxProvider store={store}>
<DApp />
</ReduxProvider>
</WalletConnectionErrorContextProvider>
</WalletConnectionAlertContextProvider>
</SidebarContextProvider>
</DocsDrawerContextProvider>
</AcreSdkProvider>
Expand Down
99 changes: 99 additions & 0 deletions dapp/src/components/ConnectWalletModal/ConnectWalletAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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",
}

function ContactSupport() {
return (
<Box as="span">
If the problem persists, contact{" "}
<Link
// TODO: Define in the new color palette
color="#0E61FE"
textDecoration="underline"
href={EXTERNAL_HREF.DISCORD}
isExternal
>
Acre support
</Link>
.
</Box>
)
}

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 are supported. Please use a compatible address or switch to a different wallet.",
},
[ConnectionAlert.NetworkMismatch]: {
title: "Incorrect network detected in your wallet.",
description:
"Please connect your wallet to the correct Bitcoin network and try again.",
},
[ConnectionAlert.Default]: {
title: "Wallet connection failed. Please try again.",
description: <ContactSupport />,
},
[ConnectionAlert.InvalidSIWWSignature]: {
title: "Invalid sign-in signature. Please try again.",
description: <ContactSupport />,
},
}

const collapseVariants: Variants = {
collapsed: { height: 0 },
expanded: { height: "auto" },
}

type ConnectWalletAlertProps = AlertProps & { type?: ConnectionAlert }

export default function ConnectWalletAlert(props: ConnectWalletAlertProps) {
const { type, status, ...restProps } = props

const data = type ? CONNECTION_ALERTS[type] : undefined

return (
<AnimatePresence initial={false}>
{data && (
<Box
as={motion.div}
variants={collapseVariants}
initial="collapsed"
animate="expanded"
exit="collapsed"
overflow="hidden"
w="full"
>
<Alert status={status} mb={6} {...restProps}>
<AlertIcon />
<VStack w="full" align="start" spacing={0}>
<AlertTitle textAlign="start">{data.title}</AlertTitle>
<AlertDescription>{data.description}</AlertDescription>
</VStack>
</Alert>
</Box>
)}
</AnimatePresence>
)
}
23 changes: 12 additions & 11 deletions dapp/src/components/ConnectWalletModal/ConnectWalletButton.tsx
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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<boolean>(false)

const hasConnectionError = connectionError || connectionStatus === "error"
const hasConnectionError = type || connectionStatus === "error"
const hasSignMessageErrorStatus = signMessageStatus === "error"
const shouldShowStatuses = isSelected && !hasConnectionError
const shouldShowRetryButton = address && hasSignMessageErrorStatus
Expand All @@ -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,
],
)

Expand All @@ -130,18 +131,18 @@ export default function ConnectWalletButton({
onError: (error: OrangeKitError) => {
const errorData = orangeKit.parseOrangeKitConnectionError(error)

if (errorData === CONNECTION_ERRORS.DEFAULT) {
if (errorData === ConnectionAlert.Default) {
console.error("Failed to connect", error)
}

setConnectionError(errorData)
setConnectionAlert(errorData)
},
})
}, [
onConnect,
connector,
onSuccessConnection,
setConnectionError,
setConnectionAlert,
isReconnecting,
])

Expand All @@ -164,7 +165,7 @@ export default function ConnectWalletButton({
if (shouldShowStatuses) return

if (!isReconnecting) onDisconnect()
resetConnectionError()
resetConnectionAlert()
resetMessageStatus()

const isInstalled = orangeKit.isWalletInstalled(connector)
Expand Down
50 changes: 0 additions & 50 deletions dapp/src/components/ConnectWalletModal/ConnectWalletErrorAlert.tsx

This file was deleted.

10 changes: 5 additions & 5 deletions dapp/src/components/ConnectWalletModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -30,7 +30,7 @@ export function ConnectWalletModalBase({
}))

const [selectedConnectorId, setSelectedConnectorId] = useState<string>()
const { connectionError, resetConnectionError } = useWalletConnectionError()
const { type, status, resetConnectionAlert } = useWalletConnectionAlert()
const isSignedMessage = useIsSignedMessage()

const handleButtonOnClick = (connector: OrangeKitConnector) => {
Expand All @@ -48,7 +48,7 @@ export function ConnectWalletModalBase({
{withCloseButton && (
<ModalCloseButton
onClick={() => {
resetConnectionError()
resetConnectionAlert()

if (!isSignedMessage) {
onDisconnect()
Expand All @@ -59,7 +59,7 @@ export function ConnectWalletModalBase({
<ModalHeader>{`Select your ${isEmbed ? "account" : "wallet"}`}</ModalHeader>

<ModalBody gap={0}>
<ConnectWalletErrorAlert {...connectionError} />
<ConnectWalletAlert type={type} status={status} />

{enabledConnectors.map((connector) => (
<ConnectWalletButton
Expand Down
27 changes: 1 addition & 26 deletions dapp/src/constants/errors.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,4 @@
import { ACTION_FLOW_TYPES, ConnectionErrorData } from "#/types"

export const CONNECTION_ERRORS: Record<string, ConnectionErrorData> = {
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.",
Expand Down
54 changes: 54 additions & 0 deletions dapp/src/contexts/WalletConnectionAlertContext.tsx
Original file line number Diff line number Diff line change
@@ -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<WalletConnectionAlertContextValue>(
{} as WalletConnectionAlertContextValue,
)

export function WalletConnectionAlertContextProvider({
children,
}: {
children: React.ReactNode
}): React.ReactElement {
const [type, setType] = useState<ConnectionAlert>()
const [status, setStatus] = useState<AlertStatus>("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<WalletConnectionAlertContextValue>(
() => ({
type,
status,
setConnectionAlert,
resetConnectionAlert,
}),
[resetConnectionAlert, setConnectionAlert, status, type],
)

return (
<WalletConnectionAlertContext.Provider value={contextValue}>
{children}
</WalletConnectionAlertContext.Provider>
)
}
Loading
Loading