Use empty props from CardGrid (#1304)
* empty for account, addressbook * staking empty screen * use multi only when values changed * lint * withCall paramPick transform * use paramPick and log things * swap logging * Display getMethod errors in withCall * Remove nested try * Use updateDb to trigger an update * fix bonding * Revert ifs * Update call.tsx * lint * stray logs
This commit is contained in:
parent
b2bc58b444
commit
b2f6d87de1
@ -38,8 +38,9 @@ class Overview extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { accounts, onStatusChange, t } = this.props;
|
||||
const { accounts, t } = this.props;
|
||||
const { isCreateOpen, isImportOpen } = this.state;
|
||||
const emptyScreen = !isCreateOpen && !isImportOpen && (!accounts || Object.keys(accounts).length === 0);
|
||||
|
||||
return (
|
||||
<CardGrid
|
||||
@ -58,19 +59,11 @@ class Overview extends React.PureComponent<Props, State> {
|
||||
/>
|
||||
</Button.Group>
|
||||
}
|
||||
isEmpty={emptyScreen}
|
||||
emptyText={t('No account yet?')}
|
||||
>
|
||||
{isCreateOpen && (
|
||||
<CreateModal
|
||||
onClose={this.toggleCreate}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{isImportOpen && (
|
||||
<ImportModal
|
||||
onClose={this.toggleImport}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{this.renderCreate()}
|
||||
{this.renderImport()}
|
||||
{accounts && Object.keys(accounts).map((address) => (
|
||||
<Account
|
||||
address={address}
|
||||
@ -81,6 +74,38 @@ class Overview extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private renderCreate () {
|
||||
const { isCreateOpen } = this.state;
|
||||
const { onStatusChange } = this.props;
|
||||
|
||||
if (!isCreateOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<CreateModal
|
||||
onClose={this.toggleCreate}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderImport () {
|
||||
const { isImportOpen } = this.state;
|
||||
const { onStatusChange } = this.props;
|
||||
|
||||
if (!isImportOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ImportModal
|
||||
onClose={this.toggleImport}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleCreate = (): void => {
|
||||
this.setState(({ isCreateOpen }) => ({
|
||||
isCreateOpen: !isCreateOpen
|
||||
|
||||
@ -31,6 +31,7 @@ class Overview extends React.PureComponent<Props, State> {
|
||||
render () {
|
||||
const { addresses, onStatusChange, t } = this.props;
|
||||
const { isCreateOpen } = this.state;
|
||||
const emptyScreen = !isCreateOpen && (!addresses || Object.keys(addresses).length === 0);
|
||||
|
||||
return (
|
||||
<CardGrid
|
||||
@ -43,6 +44,8 @@ class Overview extends React.PureComponent<Props, State> {
|
||||
/>
|
||||
</Button.Group>
|
||||
}
|
||||
isEmpty={emptyScreen}
|
||||
emptyText={t('No contact found.')}
|
||||
>
|
||||
{isCreateOpen && (
|
||||
<CreateModal
|
||||
|
||||
@ -97,8 +97,8 @@ const BOB = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty';
|
||||
console.log('Tracking balances for:', [ALICE, BOB])
|
||||
|
||||
// Subscribe and listen to several balance changes
|
||||
api.query.balances.freeBalance.multi([ALICE, BOB], (balance) => {
|
||||
console.log('Change detected, new balances: ', balance)
|
||||
api.query.balances.freeBalance.multi([ALICE, BOB], (balances) => {
|
||||
console.log('Change detected, new balances: ', balances)
|
||||
});`
|
||||
};
|
||||
|
||||
|
||||
@ -80,19 +80,20 @@ class Account extends React.PureComponent<Props, State> {
|
||||
stashId: null
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ staking_info }: Props): State | null {
|
||||
static getDerivedStateFromProps ({ accountId, staking_info }: Props): State | null {
|
||||
|
||||
if (!staking_info) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { accountId, controllerId, nextSessionId, nominators, rewardDestination, stakers, stakingLedger, stashId, validatorPrefs } = staking_info;
|
||||
const { controllerId, nextSessionId, nominators, rewardDestination, stakers, stakingLedger, stashId, validatorPrefs } = staking_info;
|
||||
const isStashNominating = nominators && nominators.length !== 0;
|
||||
const isStashValidating = !!validatorPrefs && !validatorPrefs.isEmpty && !isStashNominating;
|
||||
|
||||
return {
|
||||
controllerId: toIdString(controllerId),
|
||||
destination: rewardDestination && rewardDestination.toNumber(),
|
||||
isActiveStash: accountId.eq(stashId),
|
||||
isActiveStash: accountId === toIdString(stashId),
|
||||
isStashNominating,
|
||||
isStashValidating,
|
||||
nominees: nominators && nominators.map(toIdString),
|
||||
|
||||
@ -2,22 +2,25 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { ComponentProps } from '../types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types';
|
||||
import { withCalls, withMulti } from '@polkadot/ui-api/with';
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Button, CardGrid, Icon } from '@polkadot/ui-app';
|
||||
import createOption from '@polkadot/ui-keyring/options/item';
|
||||
import { getAddressName } from '@polkadot/ui-app/util';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Account from './Account';
|
||||
import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types';
|
||||
import StartStaking from './NewStake';
|
||||
import translate from '../translate';
|
||||
|
||||
type Props = I18nProps & ComponentProps;
|
||||
type Props = I18nProps & ComponentProps & ApiProps & {
|
||||
myControllers?: Array<string>
|
||||
};
|
||||
|
||||
type State = {
|
||||
isNewStakeOpen: boolean
|
||||
@ -30,8 +33,10 @@ class Accounts extends React.PureComponent<Props,State> {
|
||||
|
||||
render () {
|
||||
const { className, recentlyOffline, t } = this.props;
|
||||
const accounts = keyring.getAccounts();
|
||||
const { isNewStakeOpen } = this.state;
|
||||
const stashOptions = this.getStashOptions();
|
||||
const myStashes = this.getMyStashes();
|
||||
const isEmpty = !isNewStakeOpen && (!myStashes || myStashes.length === 0);
|
||||
|
||||
return (
|
||||
<CardGrid
|
||||
@ -49,9 +54,12 @@ class Accounts extends React.PureComponent<Props,State> {
|
||||
/>
|
||||
}
|
||||
className={className}
|
||||
emptyText={t('No funds staked yet.')}
|
||||
isEmpty={isEmpty}
|
||||
>
|
||||
{this.renderNewStake()}
|
||||
{accounts.map(({ address }, index) => (
|
||||
{myStashes && myStashes.map((address, index) => (
|
||||
address &&
|
||||
<Account
|
||||
accountId={address}
|
||||
key={index}
|
||||
@ -63,6 +71,31 @@ class Accounts extends React.PureComponent<Props,State> {
|
||||
);
|
||||
}
|
||||
|
||||
private getMyStashes () {
|
||||
const { myControllers, allAccounts } = this.props;
|
||||
const result: Array<string> = [];
|
||||
|
||||
if (!myControllers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
myControllers.forEach((value,index) => {
|
||||
if (value.toString() !== '') {
|
||||
allAccounts && result.push(Object.keys(allAccounts)[index]);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private getStashOptions (): Array<KeyringSectionOption> {
|
||||
const { stashes } = this.props;
|
||||
|
||||
return stashes.map((stashId) =>
|
||||
createOption(stashId, getAddressName(stashId, 'account'))
|
||||
);
|
||||
}
|
||||
|
||||
private renderNewStake () {
|
||||
const { isNewStakeOpen } = this.state;
|
||||
|
||||
@ -82,18 +115,22 @@ class Accounts extends React.PureComponent<Props,State> {
|
||||
isNewStakeOpen: !isNewStakeOpen
|
||||
}));
|
||||
}
|
||||
|
||||
private getStashOptions (): Array<KeyringSectionOption> {
|
||||
const { stashes } = this.props;
|
||||
|
||||
return stashes.map((stashId) =>
|
||||
createOption(stashId, getAddressName(stashId, 'account'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(styled(Accounts)`
|
||||
.ui--CardGrid-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
`);
|
||||
export default withMulti(
|
||||
styled(Accounts)`
|
||||
.ui--CardGrid-buttons {
|
||||
text-align: right;
|
||||
}
|
||||
`,
|
||||
translate,
|
||||
withCalls<Props>(
|
||||
['query.staking.bonded', {
|
||||
isMulti: true,
|
||||
paramPick: ({ allAccounts }: Props) => {
|
||||
return allAccounts && Object.keys(allAccounts);
|
||||
},
|
||||
propName: 'myControllers'
|
||||
}]
|
||||
)
|
||||
);
|
||||
|
||||
@ -18,8 +18,8 @@ import accountObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import basicMd from './md/basic.md';
|
||||
import Accounts from './Actions/Accounts';
|
||||
import basicMd from './md/basic.md';
|
||||
import Overview from './Overview';
|
||||
import translate from './translate';
|
||||
|
||||
@ -121,10 +121,11 @@ class App extends React.PureComponent<Props, State> {
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>) {
|
||||
return (): React.ReactNode => {
|
||||
const { controllers, recentlyOffline, stashes, validators } = this.state;
|
||||
const { balances = {} } = this.props;
|
||||
const { balances = {}, allAccounts } = this.props;
|
||||
|
||||
return (
|
||||
<Component
|
||||
allAccounts={allAccounts}
|
||||
balances={balances}
|
||||
controllers={controllers}
|
||||
recentlyOffline={recentlyOffline}
|
||||
|
||||
@ -2,9 +2,10 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountId, BlockNumber } from '@polkadot/types';
|
||||
import BN from 'bn.js';
|
||||
import { DerivedFees, DerivedBalances, DerivedBalancesMap } from '@polkadot/api-derive/types';
|
||||
import { AccountId, BlockNumber } from '@polkadot/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
export type Nominators = {
|
||||
// stash account and who is being nominated
|
||||
@ -12,6 +13,7 @@ export type Nominators = {
|
||||
};
|
||||
|
||||
export type ComponentProps = {
|
||||
allAccounts?: SubjectInfo,
|
||||
balances?: DerivedBalancesMap,
|
||||
controllers: Array<string>,
|
||||
recentlyOffline: RecentlyOfflineMap,
|
||||
|
||||
@ -18,13 +18,15 @@ interface Method {
|
||||
multi: (params: Array<any>, cb: (value?: any) => void) => Promise<any>;
|
||||
}
|
||||
|
||||
type ApiMethodInfo = [Method, Array<any>, boolean];
|
||||
|
||||
type State = CallState;
|
||||
|
||||
const NOOP = () => {
|
||||
// ignore
|
||||
};
|
||||
|
||||
export default function withCall<P extends ApiProps> (endpoint: string, { at, atProp, callOnResult, isMulti = false, params = [], paramName, paramValid = false, propName, transform = echoTransform }: Options = {}): (Inner: React.ComponentType<ApiProps>) => React.ComponentType<any> {
|
||||
export default function withCall<P extends ApiProps> (endpoint: string, { at, atProp, callOnResult, isMulti = false, params = [], paramName, paramPick, paramValid = false, propName, transform = echoTransform }: Options = {}): (Inner: React.ComponentType<ApiProps>) => React.ComponentType<any> {
|
||||
return (Inner: React.ComponentType<ApiProps>): React.ComponentType<SubtractProps<P, ApiProps>> => {
|
||||
class WithPromise extends React.Component<P, State> {
|
||||
state: State = {
|
||||
@ -46,8 +48,8 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps: any) {
|
||||
const newParams = this.getParams(this.props);
|
||||
const oldParams = this.getParams(prevProps);
|
||||
const newParams = this.getParams(this.props);
|
||||
|
||||
if (this.isActive && !isEqual(newParams, oldParams)) {
|
||||
this
|
||||
@ -93,9 +95,11 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
|
||||
}
|
||||
|
||||
private getParams (props: any): [boolean, Array<any>] {
|
||||
const paramValue = paramName
|
||||
? props[paramName]
|
||||
: undefined;
|
||||
const paramValue = paramPick
|
||||
? paramPick(props)
|
||||
: paramName
|
||||
? props[paramName]
|
||||
: undefined;
|
||||
|
||||
if (atProp) {
|
||||
at = props[atProp];
|
||||
@ -118,7 +122,7 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
|
||||
return [true, values];
|
||||
}
|
||||
|
||||
private getApiMethod (newParams: Array<any>): [Method, Array<any>, boolean] {
|
||||
private getApiMethod (newParams: Array<any>): ApiMethodInfo {
|
||||
const { api } = this.props;
|
||||
|
||||
if (endpoint === 'subscribe') {
|
||||
@ -162,29 +166,39 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
|
||||
}
|
||||
|
||||
const { api } = this.props;
|
||||
let info: ApiMethodInfo | undefined;
|
||||
|
||||
await api.isReady;
|
||||
|
||||
try {
|
||||
const [apiMethod, params, isSubscription] = this.getApiMethod(newParams);
|
||||
|
||||
assert(at || !atProp, 'Unable to perform query on non-existent at hash');
|
||||
|
||||
await this.unsubscribe();
|
||||
info = this.getApiMethod(newParams);
|
||||
} catch (error) {
|
||||
console.error(endpoint, '::', error);
|
||||
}
|
||||
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [apiMethod, params, isSubscription] = info;
|
||||
const updateCb = (value?: any) =>
|
||||
this.triggerUpdate(this.props, value);
|
||||
|
||||
await this.unsubscribe();
|
||||
|
||||
try {
|
||||
if (isSubscription) {
|
||||
const updateCb = (value?: any) =>
|
||||
this.triggerUpdate(this.props, value);
|
||||
|
||||
this.destroy = isMulti
|
||||
? await apiMethod.multi(params, updateCb)
|
||||
: await apiMethod(...params, updateCb);
|
||||
} else {
|
||||
const value: any = at
|
||||
? await apiMethod.at(at, ...params)
|
||||
: await apiMethod(...params);
|
||||
|
||||
this.triggerUpdate(this.props, value);
|
||||
updateCb(
|
||||
at
|
||||
? await apiMethod.at(at, ...params)
|
||||
: await apiMethod(...params)
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error(endpoint, '::', error);
|
||||
|
||||
@ -20,6 +20,7 @@ export type Options = {
|
||||
isMulti?: boolean,
|
||||
params?: Array<any>,
|
||||
paramName?: string,
|
||||
paramPick?: (props: any) => any,
|
||||
paramValid?: boolean,
|
||||
propName?: string,
|
||||
transform?: Transform
|
||||
|
||||
@ -14,8 +14,8 @@ type Props = CollectionProps;
|
||||
type State = CollectionState;
|
||||
|
||||
class CardGrid extends Collection<Props, State> {
|
||||
static getDerivedStateFromProps ({ children }: Props) {
|
||||
if (!children || (children as Array<any>).length <= 0) {
|
||||
static getDerivedStateFromProps ({ children, isEmpty }: Props) {
|
||||
if (isEmpty || !children || (children as Array<any>).length <= 0) {
|
||||
return { isEmpty: true, showHeader: false };
|
||||
}
|
||||
return { isEmpty: false, showHeader: true };
|
||||
|
||||
@ -11,6 +11,7 @@ export type CollectionProps = I18nProps & {
|
||||
children: React.ReactNode,
|
||||
className?: string,
|
||||
headerText?: React.ReactNode,
|
||||
isEmpty?: boolean,
|
||||
emptyText?: React.ReactNode
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user