Skip to content

Commit

Permalink
refactor: connect ledger component
Browse files Browse the repository at this point in the history
  • Loading branch information
0xKheops committed Dec 20, 2024
1 parent a6359b9 commit e5cb227
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 210 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { log } from "extension-shared"
import { FC, useCallback, useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next"

import { Spacer } from "@talisman/components/Spacer"
import {
LedgerConnectionStatus,
LedgerConnectionStatusProps,
} from "@ui/domains/Account/LedgerConnectionStatus"
import { getCustomTalismanLedgerError } from "@ui/hooks/ledger/errors"

type ConnectLedgerBaseProps = {
appName: string
isReadyCheck: () => Promise<unknown>
onReadyChanged: (ready: boolean) => void
className?: string
}

export const ConnectLedgerBase: FC<ConnectLedgerBaseProps> = ({
appName,
isReadyCheck,
onReadyChanged,
className,
}) => {
const { t } = useTranslation("admin")

// flag to prevents double connect attempt in dev mode
const refIsBusy = useRef(false)

const [connectionStatus, setConnectionStatus] = useState<LedgerConnectionStatusProps>({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const connect = useCallback(async () => {
if (refIsBusy.current) return
refIsBusy.current = true

try {
onReadyChanged?.(false)
setConnectionStatus({
status: "connecting",
message: t("Connecting to Ledger..."),
})

await isReadyCheck()

setConnectionStatus({
status: "ready",
message: t("Successfully connected to Ledger."),
})
onReadyChanged?.(true)
} catch (err) {
const error = getCustomTalismanLedgerError(err)
log.error("ConnectLedgerSubstrateGeneric", { error })
setConnectionStatus({
status: "error",
message: error.message,
onRetryClick: connect,
})
} finally {
refIsBusy.current = false
}
}, [isReadyCheck, onReadyChanged, t])

useEffect(() => {
connect()
}, [connect, isReadyCheck, onReadyChanged])

return (
<div className={className}>
<div className="text-body-secondary m-0">
{t("Connect and unlock your Ledger, then open the {{appName}} app on your Ledger.", {
appName,
})}
</div>
<Spacer small />
{!!connectionStatus && <LedgerConnectionStatus {...connectionStatus} />}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,80 +1,27 @@
import { getEthLedgerDerivationPath } from "extension-core"
import { log } from "extension-shared"
import { useCallback, useEffect, useRef, useState } from "react"
import { Trans, useTranslation } from "react-i18next"
import { FC, useCallback } from "react"

import { Spacer } from "@talisman/components/Spacer"
import {
LedgerConnectionStatus,
LedgerConnectionStatusProps,
} from "@ui/domains/Account/LedgerConnectionStatus"
import { getCustomTalismanLedgerError } from "@ui/hooks/ledger/errors"
import { useLedgerEthereum } from "@ui/hooks/ledger/useLedgerEthereum"

export const ConnectLedgerEthereum = ({
onReadyChanged,
className,
}: {
onReadyChanged?: (ready: boolean) => void
import { ConnectLedgerBase } from "./ConnectLedgerBase"

export const ConnectLedgerEthereum: FC<{
onReadyChanged: (ready: boolean) => void
className?: string
}) => {
const { t } = useTranslation("admin")
}> = ({ onReadyChanged, className }) => {
const { getAddress } = useLedgerEthereum()

// flag to prevents double connect attempt in dev mode
const refIsBusy = useRef(false)

const [connectionStatus, setConnectionStatus] = useState<LedgerConnectionStatusProps>({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const connect = useCallback(async () => {
if (refIsBusy.current) return
refIsBusy.current = true

try {
onReadyChanged?.(false)
setConnectionStatus({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const derivationPath = getEthLedgerDerivationPath("LedgerLive")
await getAddress(derivationPath)

setConnectionStatus({
status: "ready",
message: t("Successfully connected to Ledger."),
})
onReadyChanged?.(true)
} catch (err) {
const error = getCustomTalismanLedgerError(err)
log.error("ConnectLedgerSubstrateGeneric", { error })
setConnectionStatus({
status: "error",
message: error.message,
onRetryClick: connect,
})
} finally {
refIsBusy.current = false
}
}, [getAddress, onReadyChanged, t])

useEffect(() => {
connect()
}, [connect, getAddress, onReadyChanged])
const isReadyCheck = useCallback(() => {
const derivationPath = getEthLedgerDerivationPath("LedgerLive")
return getAddress(derivationPath)
}, [getAddress])

return (
<div className={className}>
<div className="text-body-secondary m-0">
<Trans t={t}>
Connect and unlock your Ledger, then open the <span className="text-body">Ethereum</span>{" "}
app on your Ledger.
</Trans>
</div>
<Spacer small />
<LedgerConnectionStatus {...connectionStatus} />
</div>
<ConnectLedgerBase
isReadyCheck={isReadyCheck}
appName="Ethereum"
onReadyChanged={onReadyChanged}
className={className}
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,85 +1,30 @@
import { log } from "extension-shared"
import { FC, useCallback, useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import { FC, useCallback } from "react"

import { Spacer } from "@talisman/components/Spacer"
import {
LedgerConnectionStatus,
LedgerConnectionStatusProps,
} from "@ui/domains/Account/LedgerConnectionStatus"
import { getPolkadotLedgerDerivationPath } from "@ui/hooks/ledger/common"
import { getCustomTalismanLedgerError } from "@ui/hooks/ledger/errors"
import { useLedgerSubstrateAppByName } from "@ui/hooks/ledger/useLedgerSubstrateApp"
import { useLedgerSubstrateGeneric } from "@ui/hooks/ledger/useLedgerSubstrateGeneric"

type ConnectLedgerSubstrateGenericProps = {
onReadyChanged?: (ready: boolean) => void
import { ConnectLedgerBase } from "./ConnectLedgerBase"

export const ConnectLedgerSubstrateGeneric: FC<{
onReadyChanged: (ready: boolean) => void
className?: string
legacyAppName?: string | null
}

export const ConnectLedgerSubstrateGeneric: FC<ConnectLedgerSubstrateGenericProps> = ({
onReadyChanged,
className,
legacyAppName,
}) => {
const { t } = useTranslation("admin")
}> = ({ onReadyChanged, className, legacyAppName }) => {
const legacyApp = useLedgerSubstrateAppByName(legacyAppName)
const { getAddress } = useLedgerSubstrateGeneric({ legacyApp })

// flag to prevents double connect attempt in dev mode
const refIsBusy = useRef(false)

const [connectionStatus, setConnectionStatus] = useState<LedgerConnectionStatusProps>({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const connect = useCallback(async () => {
if (refIsBusy.current) return
refIsBusy.current = true

try {
onReadyChanged?.(false)
setConnectionStatus({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const bip44path = getPolkadotLedgerDerivationPath({ legacyApp })
await getAddress(bip44path)

setConnectionStatus({
status: "ready",
message: t("Successfully connected to Ledger."),
})
onReadyChanged?.(true)
} catch (err) {
const error = getCustomTalismanLedgerError(err)
log.error("ConnectLedgerSubstrateGeneric", { error })
setConnectionStatus({
status: "error",
message: error.message,
onRetryClick: connect,
})
} finally {
refIsBusy.current = false
}
}, [getAddress, legacyApp, onReadyChanged, t])

useEffect(() => {
connect()
}, [connect, getAddress, legacyApp, onReadyChanged])
const isReadyCheck = useCallback(() => {
const derivationPath = getPolkadotLedgerDerivationPath({ legacyApp })
return getAddress(derivationPath)
}, [getAddress, legacyApp])

return (
<div className={className}>
<div className="text-body-secondary m-0">
{t("Connect and unlock your Ledger, then open the {{appName}} app on your Ledger.", {
appName: legacyApp ? "Polkadot Migration" : "Polkadot",
})}
</div>
<Spacer small />
{!!connectionStatus && <LedgerConnectionStatus {...connectionStatus} />}
</div>
<ConnectLedgerBase
isReadyCheck={isReadyCheck}
appName={legacyAppName ? "Polkadot Migration" : "Polkadot"}
onReadyChanged={onReadyChanged}
className={className}
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,83 +1,26 @@
import { log } from "extension-shared"
import { FC, useCallback, useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import { FC, useCallback } from "react"

import { Spacer } from "@talisman/components/Spacer"
import {
LedgerConnectionStatus,
LedgerConnectionStatusProps,
} from "@ui/domains/Account/LedgerConnectionStatus"
import { getCustomTalismanLedgerError } from "@ui/hooks/ledger/errors"
import { useLedgerSubstrateLegacy } from "@ui/hooks/ledger/useLedgerSubstrateLegacy"
import { useChain } from "@ui/state"

type ConnectLedgerSubstrateLegacyProps = {
import { ConnectLedgerBase } from "./ConnectLedgerBase"

export const ConnectLedgerSubstrateLegacy: FC<{
chainId: string
onReadyChanged?: (ready: boolean) => void
onReadyChanged: (ready: boolean) => void
className?: string
}

export const ConnectLedgerSubstrateLegacy: FC<ConnectLedgerSubstrateLegacyProps> = ({
chainId,
onReadyChanged,
className,
}) => {
const { t } = useTranslation("admin")
}> = ({ chainId, onReadyChanged, className }) => {
const chain = useChain(chainId)
const { app, getAddress } = useLedgerSubstrateLegacy(chain?.genesisHash)

// flag to prevents double connect attempt in dev mode
const refIsBusy = useRef(false)

const [connectionStatus, setConnectionStatus] = useState<LedgerConnectionStatusProps>({
status: "connecting",
message: t("Connecting to Ledger..."),
})

const connect = useCallback(async () => {
if (refIsBusy.current) return
refIsBusy.current = true

try {
onReadyChanged?.(false)
setConnectionStatus({
status: "connecting",
message: t("Connecting to Ledger..."),
})

await getAddress(0, 0)

setConnectionStatus({
status: "ready",
message: t("Successfully connected to Ledger."),
})
onReadyChanged?.(true)
} catch (err) {
const error = getCustomTalismanLedgerError(err)
log.error("ConnectLedgerSubstrateGeneric", { error })
setConnectionStatus({
status: "error",
message: error.message,
onRetryClick: connect,
})
} finally {
refIsBusy.current = false
}
}, [getAddress, onReadyChanged, t])

useEffect(() => {
connect()
}, [connect, getAddress, onReadyChanged])
const isReadyCheck = useCallback(() => getAddress(0, 0), [getAddress])

return (
<div className={className}>
<div className="text-body-secondary m-0">
{t("Connect and unlock your Ledger, then open the {{appName}} app on your Ledger.", {
appName: app?.name ?? "UNKNOWN_APP",
})}
</div>
<Spacer small />
{!!connectionStatus && <LedgerConnectionStatus {...connectionStatus} />}
</div>
<ConnectLedgerBase
isReadyCheck={isReadyCheck}
appName={app?.name ?? "Unknown App"}
onReadyChanged={onReadyChanged}
className={className}
/>
)
}

0 comments on commit e5cb227

Please sign in to comment.