Skip to content

Commit

Permalink
feat: error UI
Browse files Browse the repository at this point in the history
  • Loading branch information
0xKheops committed Aug 3, 2023
1 parent 9c201be commit 2e46625
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Accordion, AccordionIcon } from "@talisman/components/Accordion"
import { CornerDownRightIcon } from "@talisman/theme/icons"
import { shortenAddress } from "@talisman/util/shortenAddress"
import { Token } from "@talismn/chaindata-provider"
import { AccountIcon } from "@ui/domains/Account/AccountIcon"
Expand Down Expand Up @@ -104,7 +105,7 @@ export const DcentAccountRow: FC<{ accountInfo: DcentAccountInfo }> = ({ account
/>
</div>
<Accordion isOpen={isOpen}>
<div className="pl-[6rem]">
<div className="relative pl-[6rem]">
{accountInfo.tokens.map((token) => (
<DcentAccountTokenRow
key={token.id}
Expand All @@ -113,6 +114,7 @@ export const DcentAccountRow: FC<{ accountInfo: DcentAccountInfo }> = ({ account
balances={balances}
/>
))}
<CornerDownRightIcon className="text-body-disabled absolute left-12 top-6 text-lg" />
</div>
</Accordion>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const EthSignMessageRequest = () => {
onSignature={approveHardware}
onReject={reject}
containerId="main"
showCancelButton
/>
) : account.isHardware ? (
<LedgerEthereum
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const SendFundsDcentSubstrate = () => {
onClick={sendToLedger(true)}
processing={signed}
>
{t("Approve on Dcent")}
{t("Approve on D'CENT")}
</Button>
)

Expand Down
36 changes: 36 additions & 0 deletions apps/extension/src/ui/domains/Sign/ErrorMessageDrawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { AlertCircleIcon } from "@talisman/theme/icons"
import { FC, useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { Button, Drawer } from "talisman-ui"

export const ErrorMessageDrawer: FC<{
message: string | undefined
containerId: string | undefined
onDismiss: () => void
}> = ({ message, containerId, onDismiss }) => {
const { t } = useTranslation()

// keep message in memory to prevent flickering on slide out
const [content, setContent] = useState<string>()

useEffect(() => {
setContent(message)
}, [message])

return (
<Drawer
anchor="bottom"
isOpen={!!content && message === content}
containerId={containerId}
onDismiss={onDismiss}
>
<div className="bg-grey-800 text-alert-warn flex w-full flex-col items-center gap-4 rounded-t-xl p-12 text-sm">
<AlertCircleIcon className={"text-[3rem]"} />
<p className="mt-2">{content}</p>
<Button className="mt-8 w-full" primary onClick={onDismiss}>
{t("Dismiss")}
</Button>
</div>
</Drawer>
)
}
49 changes: 25 additions & 24 deletions apps/extension/src/ui/domains/Sign/SignDcentEthereum.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AccountJsonDcent } from "@core/domains/accounts/types"
import { EthSignMessageMethod } from "@core/domains/signing/types"
import i18next from "@core/i18nConfig"
import { log } from "@core/log"
import { isHexString } from "@ethereumjs/util"
import { hexToString } from "@polkadot/util"
import { HexString } from "@polkadot/util/types"
Expand All @@ -10,14 +11,16 @@ import DcentWebConnector from "dcent-web-connector"
import { ethers } from "ethers"
import { FC, useCallback, useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { Drawer } from "talisman-ui"
import { Button } from "talisman-ui"

import { ErrorMessageDrawer } from "./ErrorMessageDrawer"

type DcentEthereumProps = {
account: AccountJsonDcent
method: EthSignMessageMethod | "eth_sendTransaction"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
payload: any // string message, typed object for eip712, TransactionRequest for tx
showCancelButton?: boolean
containerId?: string
className?: string
onSignature?: ({ signature }: { signature: HexString }) => void | Promise<void>
Expand Down Expand Up @@ -72,9 +75,7 @@ const signWithDcent = async (
type,
maxPriorityFeePerGas,
maxFeePerGas,
} = await ethers.utils.resolveProperties(
payload.transaction as ethers.providers.TransactionRequest
)
} = await ethers.utils.resolveProperties(payload as ethers.providers.TransactionRequest)

const baseTx: ethers.utils.UnsignedTransaction = {
to,
Expand Down Expand Up @@ -136,14 +137,15 @@ const SignDcentEthereum: FC<DcentEthereumProps> = ({
payload,
className,
containerId,
showCancelButton,
onWaitingChanged, // TODO to manage error, maybe rename and change to a have a boolean indicating if waiting signature or not (then call again with false )
onSignature,
onReject,
}) => {
const { t } = useTranslation("request")
const [isSigning, setIsSigning] = useState(false)
const [isSigned, setIsSigned] = useState(false)
const [error, setError] = useState<DcentError>()
const [displayedErrorMessage, setDisplayedErrorMessage] = useState<string>()

// reset
useEffect(() => {
Expand All @@ -155,19 +157,23 @@ const SignDcentEthereum: FC<DcentEthereumProps> = ({
return
}
setIsSigning(true)
setError(undefined)
setDisplayedErrorMessage(undefined)
onWaitingChanged?.(true)
try {
const signature = await signWithDcent(method, payload, account.path)
await onSignature({ signature })
onSignature({ signature })
setIsSigned(true)
} catch (err) {
setError(err as DcentError)
log.error("Failed to sign", { err })
if (err instanceof DcentError) {
if (err.code === "user_cancel") onReject?.()
else setDisplayedErrorMessage(err.message)
} else setDisplayedErrorMessage((err as Error).message ?? "Failed to sign")
setIsSigning(false)
}
onWaitingChanged?.(false)
setIsSigning(false)
}, [onSignature, onWaitingChanged, method, payload, account])
}, [onSignature, payload, account, onWaitingChanged, method, onReject])

const handleCancelClick = useCallback(() => {
onReject()
Expand All @@ -182,23 +188,18 @@ const SignDcentEthereum: FC<DcentEthereumProps> = ({
onClick={signLedger}
processing={isSigning || isSigned}
>
{t("Approve on DCENT")}
</Button>
<Button className="w-full" onClick={handleCancelClick}>
{t("Cancel")}
{t("Approve on D'CENT")}
</Button>
{error && (
<Drawer
anchor="bottom"
isOpen
containerId={containerId}
onDismiss={() => setError(undefined)}
>
<div>
[{error.code}] {error.message}
</div>
</Drawer>
{showCancelButton && (
<Button className="w-full" onClick={handleCancelClick}>
{t("Cancel")}
</Button>
)}
<ErrorMessageDrawer
message={displayedErrorMessage}
containerId={containerId}
onDismiss={() => setDisplayedErrorMessage(undefined)}
/>
</div>
)
}
Expand Down
77 changes: 30 additions & 47 deletions apps/extension/src/ui/domains/Sign/SignDcentSubstrate.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SignerPayloadJSON, SignerPayloadRaw } from "@core/domains/signing/types"
import { log } from "@core/log"
import { getTypeRegistry } from "@core/util/getTypeRegistry"
import { isJsonPayload } from "@core/util/isJsonPayload"
import { HexString } from "@polkadot/util/types"
Expand All @@ -9,9 +10,11 @@ import useChainByGenesisHash from "@ui/hooks/useChainByGenesisHash"
import useToken from "@ui/hooks/useToken"
import { DcentError, dcentCall } from "@ui/util/dcent"
import DcentWebConnector from "dcent-web-connector"
import { FC, useCallback, useMemo, useState } from "react"
import { FC, useCallback, useEffect, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import { Button, Drawer } from "talisman-ui"
import { Button } from "talisman-ui"

import { ErrorMessageDrawer } from "./ErrorMessageDrawer"

export type DcentSubstratePayload = {
coinType: string
Expand Down Expand Up @@ -93,18 +96,14 @@ export const SignDcentSubstrate: FC<{
fee: string
containerId?: string
className?: string

showCancelButton?: boolean
onCancel: () => void
onSigned: (signature: HexString) => void
}> = ({ payload, fee, containerId, className, onCancel, onSigned }) => {
}> = ({ payload, fee, showCancelButton, containerId, className, onCancel, onSigned }) => {
const { t } = useTranslation("admin")
const {
// isValid,
errorMessage,
dcentTx,
} = useDcentPayload(payload, fee)
const { errorMessage, dcentTx } = useDcentPayload(payload, fee)

const [error, setError] = useState<DcentError>()
const [displayedErrorMessage, setDisplayedErrorMessage] = useState<string>()
const [isSigning, setIsSigning] = useState(false)

type DcentResponseSignature = {
Expand All @@ -114,7 +113,7 @@ export const SignDcentSubstrate: FC<{
const handleSendClick = useCallback(async () => {
if (!dcentTx) return
setIsSigning(true)
setError(undefined)
setDisplayedErrorMessage(undefined)
try {
const { signed_tx } = await dcentCall<DcentResponseSignature>(() =>
DcentWebConnector.getPolkadotSignedTransaction(dcentTx)
Expand All @@ -124,14 +123,22 @@ export const SignDcentSubstrate: FC<{
// prefix with ed25519
return onSigned(`0x00${signed_tx.substring(2)}`)
} catch (err) {
setError(err as DcentError)
log.error("Failed to sign", { err })
if (err instanceof DcentError) {
if (err.code === "user_cancel") onCancel?.()
else setDisplayedErrorMessage(err.message ?? "Failed to sign")
} else setDisplayedErrorMessage((err as Error).message ?? "Failed to sign")
}
setIsSigning(false)
}, [dcentTx, onSigned])
}, [dcentTx, onCancel, onSigned])

useEffect(() => {
// error from constructing payload
if (errorMessage) setDisplayedErrorMessage(errorMessage)
}, [errorMessage])

return (
<div className={classNames("flex w-full flex-col gap-6", className)}>
{errorMessage && <div>errorMessage : {errorMessage}</div>}
<Button
className="w-full"
disabled={!dcentTx}
Expand All @@ -141,40 +148,16 @@ export const SignDcentSubstrate: FC<{
>
{t("Approve on D'CENT")}
</Button>
{/* {!error && (
<>
{isReady && !autoSend ? (
<Button className="w-full" primary onClick={handleSendClick}>
{t("Approve on D'CENT")}
</Button>
) : (
!isSigned && (
<LedgerConnectionStatus {...{ ...connectionStatus }} refresh={_onRefresh} />
)
)}
</>
)} */}
<Button className="w-full" onClick={onCancel}>
{t("Cancel")}
</Button>
{error && (
<Drawer
anchor="bottom"
isOpen
containerId={containerId}
onDismiss={() => setError(undefined)}
>
{/* Shouldn't be a LedgerSigningStatus, just an error message */}
{/* <LedgerSigningStatus
message={error ? error : ""}
status={error ? "error" : isSigning ? "signing" : undefined}
confirm={onReject}
/> */}
<div>
[{error.code}] {error.message}
</div>
</Drawer>
{showCancelButton && (
<Button className="w-full" onClick={onCancel}>
{t("Cancel")}
</Button>
)}
<ErrorMessageDrawer
message={displayedErrorMessage}
containerId={containerId}
onDismiss={() => setDisplayedErrorMessage(undefined)}
/>
</div>
)
}

0 comments on commit 2e46625

Please sign in to comment.