187 lines
5.2 KiB
TypeScript
187 lines
5.2 KiB
TypeScript
// Copyright 2019-2024 @polkadot/extension-ui authors & contributors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { HexString } from '@polkadot/util/types';
|
|
|
|
import { faSync } from '@fortawesome/free-solid-svg-icons';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
|
|
import { settings } from '@polkadot/ui-settings';
|
|
|
|
import { ActionContext, Address, Button, ButtonArea, Dropdown, VerticalSpace, Warning } from '../components/index.js';
|
|
import { useLedger, useTranslation } from '../hooks/index.js';
|
|
import { createAccountHardware } from '../messaging.js';
|
|
import { Header, Name } from '../partials/index.js';
|
|
import { styled } from '../styled.js';
|
|
import ledgerChains from '../util/legerChains.js';
|
|
|
|
interface AccOption {
|
|
text: string;
|
|
value: number;
|
|
}
|
|
|
|
interface NetworkOption {
|
|
text: string;
|
|
value: string | null;
|
|
}
|
|
|
|
const AVAIL: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
|
|
|
|
interface Props {
|
|
className?: string;
|
|
}
|
|
|
|
function ImportLedger ({ className }: Props): React.ReactElement {
|
|
const { t } = useTranslation();
|
|
const [accountIndex, setAccountIndex] = useState<number>(0);
|
|
const [addressOffset, setAddressOffset] = useState<number>(0);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [isBusy, setIsBusy] = useState(false);
|
|
const [genesis, setGenesis] = useState<HexString | null>(null);
|
|
const onAction = useContext(ActionContext);
|
|
const [name, setName] = useState<string | null>(null);
|
|
const { address, error: ledgerError, isLoading: ledgerLoading, isLocked: ledgerLocked, refresh, warning: ledgerWarning } = useLedger(genesis, accountIndex, addressOffset);
|
|
|
|
useEffect(() => {
|
|
if (address) {
|
|
settings.set({ ledgerConn: 'webusb' });
|
|
}
|
|
}, [address]);
|
|
|
|
const accOps = useRef(AVAIL.map((value): AccOption => ({
|
|
text: t('Account type {{index}}', { replace: { index: value } }),
|
|
value
|
|
})));
|
|
|
|
const addOps = useRef(AVAIL.map((value): AccOption => ({
|
|
text: t('Address index {{index}}', { replace: { index: value } }),
|
|
value
|
|
})));
|
|
|
|
const networkOps = useRef(
|
|
[{
|
|
text: t('Select network'),
|
|
value: ''
|
|
},
|
|
...ledgerChains.map(({ displayName, genesisHash }): NetworkOption => ({
|
|
text: displayName,
|
|
value: genesisHash[0]
|
|
}))]
|
|
);
|
|
|
|
const _onSave = useCallback(
|
|
() => {
|
|
if (address && genesis && name) {
|
|
setIsBusy(true);
|
|
|
|
createAccountHardware(address, 'ledger', accountIndex, addressOffset, name, genesis)
|
|
.then(() => onAction('/'))
|
|
.catch((error: Error) => {
|
|
console.error(error);
|
|
|
|
setIsBusy(false);
|
|
setError(error.message);
|
|
});
|
|
}
|
|
},
|
|
[accountIndex, address, addressOffset, genesis, name, onAction]
|
|
);
|
|
|
|
// select element is returning a string
|
|
const _onSetAccountIndex = useCallback((value: number) => setAccountIndex(Number(value)), []);
|
|
const _onSetAddressOffset = useCallback((value: number) => setAddressOffset(Number(value)), []);
|
|
|
|
return (
|
|
<>
|
|
<Header
|
|
showBackArrow
|
|
text={t('Import Ledger Account')}
|
|
/>
|
|
<div className={className}>
|
|
<Address
|
|
address={address}
|
|
genesisHash={genesis}
|
|
isExternal
|
|
isHardware
|
|
name={name}
|
|
/>
|
|
<Dropdown
|
|
className='network'
|
|
label={t('Network')}
|
|
onChange={setGenesis}
|
|
options={networkOps.current}
|
|
value={genesis}
|
|
/>
|
|
{!!genesis && !!address && !ledgerError && (
|
|
<Name
|
|
onChange={setName}
|
|
value={name || ''}
|
|
/>
|
|
)}
|
|
{!!name && (
|
|
<>
|
|
<Dropdown
|
|
className='accountType'
|
|
isDisabled={ledgerLoading}
|
|
label={t('account type')}
|
|
onChange={_onSetAccountIndex}
|
|
options={accOps.current}
|
|
value={accountIndex}
|
|
/>
|
|
<Dropdown
|
|
className='accountIndex'
|
|
isDisabled={ledgerLoading}
|
|
label={t('address index')}
|
|
onChange={_onSetAddressOffset}
|
|
options={addOps.current}
|
|
value={addressOffset}
|
|
/>
|
|
</>
|
|
)}
|
|
{!!ledgerWarning && (
|
|
<Warning>
|
|
{ledgerWarning}
|
|
</Warning>
|
|
)}
|
|
{(!!error || !!ledgerError) && (
|
|
<Warning
|
|
isDanger
|
|
>
|
|
{error || ledgerError}
|
|
</Warning>
|
|
)}
|
|
</div>
|
|
<VerticalSpace />
|
|
<ButtonArea>
|
|
{ledgerLocked
|
|
? (
|
|
<Button
|
|
isBusy={ledgerLoading || isBusy}
|
|
onClick={refresh}
|
|
>
|
|
<FontAwesomeIcon icon={faSync} />
|
|
{t('Refresh')}
|
|
</Button>
|
|
)
|
|
: (
|
|
<Button
|
|
isBusy={ledgerLoading || isBusy}
|
|
isDisabled={!!error || !!ledgerError || !address || !genesis}
|
|
onClick={_onSave}
|
|
>
|
|
{t('Import Account')}
|
|
</Button>
|
|
)
|
|
}
|
|
</ButtonArea>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default styled(ImportLedger)<Props>`
|
|
.refreshIcon {
|
|
margin-right: 0.3rem;
|
|
}
|
|
`;
|