diff --git a/packages/app-js/src/Playground.tsx b/packages/app-js/src/Playground.tsx index 6a84b23fcf0d..7745715133f6 100644 --- a/packages/app-js/src/Playground.tsx +++ b/packages/app-js/src/Playground.tsx @@ -245,7 +245,6 @@ export default styled(Playground)` } .js--Dropdown { - margin-right: 100px; position: relative; z-index: 200; diff --git a/packages/react-api/src/Api.tsx b/packages/react-api/src/Api.tsx index 4432665cd8d3..25873989ffbe 100644 --- a/packages/react-api/src/Api.tsx +++ b/packages/react-api/src/Api.tsx @@ -2,14 +2,12 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { ProviderInterface } from '@polkadot/rpc-provider/types'; import { QueueTxPayloadAdd, QueueTxMessageSetStatus } from '@polkadot/react-components/Status/types'; -import { ApiProps } from './types'; +import { ApiState } from './types'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import ApiPromise from '@polkadot/api/promise'; import { isWeb3Injected, web3Accounts, web3Enable } from '@polkadot/extension-dapp'; -import defaults from '@polkadot/rpc-provider/defaults'; import { WsProvider } from '@polkadot/rpc-provider'; import { TokenUnit } from '@polkadot/react-components/InputNumber'; import keyring from '@polkadot/ui-keyring'; @@ -31,7 +29,7 @@ interface Props { url?: string; } -interface State extends ApiProps { +interface State extends ApiState { chain?: string | null; } @@ -50,163 +48,100 @@ let api: ApiPromise; export { api }; -export default class Api extends React.PureComponent { - public state: State = {} as unknown as State; +async function loadOnReady (api: ApiPromise): Promise { + const [properties, _systemChain, _systemName, _systemVersion, injectedAccounts] = await Promise.all([ + api.rpc.system.properties(), + api.rpc.system.chain(), + api.rpc.system.name(), + api.rpc.system.version(), + web3Accounts().then((accounts): InjectedAccountExt[] => + accounts.map(({ address, meta }): InjectedAccountExt => ({ + address, + meta: { + ...meta, + name: `${meta.name} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})` + } + })) + ) + ]); + const ss58Format = uiSettings.prefix === -1 + ? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber() + : uiSettings.prefix; + const tokenSymbol = properties.tokenSymbol.unwrapOr('DEV').toString(); + const tokenDecimals = properties.tokenDecimals.unwrapOr(DEFAULT_DECIMALS).toNumber(); + const systemChain = _systemChain + ? _systemChain.toString() + : ''; + const isDevelopment = isTestChain(systemChain); + + console.log('api: found chain', systemChain, JSON.stringify(properties)); + + // first setup the UI helpers + formatBalance.setDefaults({ + decimals: tokenDecimals, + unit: tokenSymbol + }); + TokenUnit.setAbbr(tokenSymbol); + + // finally load the keyring + keyring.loadAll({ + addressPrefix: ss58Format, + genesisHash: api.genesisHash, + isDevelopment, + ss58Format, + type: 'ed25519' + }, injectedAccounts); + + const defaultSection = Object.keys(api.tx)[0]; + const defaultMethod = Object.keys(api.tx[defaultSection])[0]; + const apiDefaultTx = api.tx[defaultSection][defaultMethod]; + const apiDefaultTxSudo = (api.tx.system && api.tx.system.setCode) || apiDefaultTx; + const isSubstrateV2 = !!Object.keys(api.consts).length; + + return { + apiDefaultTx, + apiDefaultTxSudo, + isApiReady: true, + isDevelopment, + isSubstrateV2, + systemChain, + systemName: _systemName.toString(), + systemVersion: _systemVersion.toString() + } as State; +} - constructor (props: Props) { - super(props); +export default function Api ({ children, queuePayload, queueSetTxStatus, url }: Props): React.ReactElement | null { + const [state, setState] = useState({ isApiReady: false } as Partial as State); + const [isApiConnected, setIsApiConnected] = useState(false); + const [isWaitingInjected, setIsWaitingInjected] = useState(isWeb3Injected); - const { queuePayload, queueSetTxStatus, url } = props; + // initial initialization + useEffect((): void => { const provider = new WsProvider(url); const signer = new ApiSigner(queuePayload, queueSetTxStatus); - const setApi = (provider: ProviderInterface): void => { - api = this.createApi(provider, signer); - - this.setState({ api }, (): void => { - this.subscribeEvents(); - }); - }; - const setApiUrl = (url: string = defaults.WS_URL): void => - setApi(new WsProvider(url)); - - api = this.createApi(provider, signer); - - this.state = { - api, - isApiConnected: false, - isApiReady: false, - isSubstrateV2: true, - isWaitingInjected: isWeb3Injected, - setApiUrl - } as unknown as State; - } - - private createApi (provider: ProviderInterface, signer: ApiSigner): ApiPromise { - return new ApiPromise({ - provider, - registry, - signer, - typesChain, - typesSpec - }); - } - - public componentDidMount (): void { - this.subscribeEvents(); - - injectedPromise - .then((): void => this.setState({ isWaitingInjected: false })) - .catch((error: Error) => console.error(error)); - } - - private subscribeEvents (): void { - const { api } = this.state; - - api.on('connected', (): void => { - this.setState({ isApiConnected: true }); - }); - - api.on('disconnected', (): void => { - this.setState({ isApiConnected: false }); - }); + api = new ApiPromise({ provider, registry, signer, typesChain, typesSpec }); + api.on('connected', (): void => setIsApiConnected(true)); + api.on('disconnected', (): void => setIsApiConnected(false)); api.on('ready', async (): Promise => { try { - await this.loadOnReady(api); + setState(await loadOnReady(api)); } catch (error) { console.error('Unable to load chain', error); } }); - } - - private async loadOnReady (api: ApiPromise): Promise { - const [properties, _systemChain, _systemName, _systemVersion, injectedAccounts] = await Promise.all([ - api.rpc.system.properties(), - api.rpc.system.chain(), - api.rpc.system.name(), - api.rpc.system.version(), - web3Accounts().then((accounts): InjectedAccountExt[] => - accounts.map(({ address, meta }): InjectedAccountExt => ({ - address, - meta: { - ...meta, - name: `${meta.name} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})` - } - })) - ) - ]); - const ss58Format = uiSettings.prefix === -1 - ? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber() - : uiSettings.prefix; - const tokenSymbol = properties.tokenSymbol.unwrapOr('DEV').toString(); - const tokenDecimals = properties.tokenDecimals.unwrapOr(DEFAULT_DECIMALS).toNumber(); - const systemChain = _systemChain - ? _systemChain.toString() - : ''; - const isDevelopment = isTestChain(systemChain); - - console.log('api: found chain', systemChain, JSON.stringify(properties)); - - // first setup the UI helpers - formatBalance.setDefaults({ - decimals: tokenDecimals, - unit: tokenSymbol - }); - TokenUnit.setAbbr(tokenSymbol); - - // finally load the keyring - keyring.loadAll({ - addressPrefix: ss58Format, - genesisHash: api.genesisHash, - isDevelopment, - ss58Format, - type: 'ed25519' - }, injectedAccounts); - - const defaultSection = Object.keys(api.tx)[0]; - const defaultMethod = Object.keys(api.tx[defaultSection])[0]; - const apiDefaultTx = api.tx[defaultSection][defaultMethod]; - const apiDefaultTxSudo = - (api.tx.system && api.tx.system.setCode) || // 2.x - (api.tx.consensus && api.tx.consensus.setCode) || // 1.x - apiDefaultTx; // other - const isSubstrateV2 = !!Object.keys(api.consts).length; - - this.setState({ - apiDefaultTx, - apiDefaultTxSudo, - isApiReady: true, - isDevelopment, - isSubstrateV2, - systemChain, - systemName: _systemName.toString(), - systemVersion: _systemVersion.toString() - }); - } - - public render (): React.ReactNode { - const { api, apiDefaultTx, apiDefaultTxSudo, isApiConnected, isApiReady, isDevelopment, isSubstrateV2, isWaitingInjected, setApiUrl, systemChain, systemName, systemVersion } = this.state; - - return ( - - {this.props.children} + + injectedPromise + .then((): void => setIsWaitingInjected(false)) + .catch((error: Error) => console.error(error)); + }, []); + + return api + ? ( + + {children} - ); - } + ) + : null; } diff --git a/packages/react-api/src/types.ts b/packages/react-api/src/types.ts index 37104d8a975f..c7cbe40becb9 100644 --- a/packages/react-api/src/types.ts +++ b/packages/react-api/src/types.ts @@ -15,21 +15,23 @@ export interface BareProps { style?: Record; } -export interface ApiProps { - api: ApiPromise; +export interface ApiState { apiDefaultTx: SubmittableExtrinsicFunction; apiDefaultTxSudo: SubmittableExtrinsicFunction; - isApiConnected: boolean; isApiReady: boolean; isDevelopment: boolean; isSubstrateV2: boolean; - isWaitingInjected: boolean; - setApiUrl: (url?: string) => void; systemChain: string; systemName: string; systemVersion: string; } +export interface ApiProps extends ApiState { + api: ApiPromise; + isWaitingInjected: boolean; + isApiConnected: boolean; +} + export interface OnChangeCbObs { next: (value?: any) => any; }