Fix Address add flicker (#309)
* Fix Address add flicker
* Clenaup unused
* use getDerivedState in Tabs
* Mark functions private
* Creator autoFocus on Input
* No extra {} on proptype
This commit is contained in:
parent
a5e1fa003d
commit
b903f63ff3
@ -87,6 +87,7 @@ class Creator extends React.PureComponent<Props, State> {
|
||||
<div className='grow'>
|
||||
<div className='ui--row'>
|
||||
<Input
|
||||
autoFocus
|
||||
className='full'
|
||||
isError={!isAddressValid}
|
||||
label={t('creator.address', {
|
||||
|
||||
@ -12,15 +12,11 @@ import Input from '@polkadot/ui-app/Input';
|
||||
import AddressSummary from '@polkadot/ui-app/AddressSummary';
|
||||
import InputAddress from '@polkadot/ui-app/InputAddress';
|
||||
import keyring from '@polkadot/ui-keyring/index';
|
||||
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
|
||||
import withObservableBase from '@polkadot/ui-react-rx/with/observableBase';
|
||||
|
||||
import Forgetting from './Forgetting';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
addressAll?: Array<any>
|
||||
};
|
||||
type Props = I18nProps;
|
||||
|
||||
type State = {
|
||||
current: KeyringAddress | null,
|
||||
@ -93,15 +89,9 @@ class Editor extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
renderData () {
|
||||
const { addressAll, t } = this.props;
|
||||
const { t } = this.props;
|
||||
const { current, editedName } = this.state;
|
||||
|
||||
if (!addressAll || !Object.keys(addressAll).length) {
|
||||
return t('editor.none', {
|
||||
defaultValue: 'There are no saved addresses. Add some first.'
|
||||
});
|
||||
}
|
||||
|
||||
const address = current
|
||||
? current.address()
|
||||
: undefined;
|
||||
@ -245,6 +235,4 @@ class Editor extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
export default withObservableBase(
|
||||
addressObservable.subject, { propName: 'addressAll' }
|
||||
)(translate(Editor));
|
||||
export default translate(Editor);
|
||||
|
||||
@ -3,29 +3,31 @@
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
|
||||
import Tabs from '@polkadot/ui-app/Tabs';
|
||||
import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
|
||||
import withObservableBase from '@polkadot/ui-react-rx/with/observableBase';
|
||||
|
||||
import { hasNoAddresses } from './util/addresses';
|
||||
import Creator from './Creator';
|
||||
import Editor from './Editor';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
addressAll?: Array<any>,
|
||||
allAddresses?: SubjectInfo,
|
||||
basePath: string
|
||||
};
|
||||
|
||||
type Actions = 'create' | 'edit';
|
||||
|
||||
type State = {
|
||||
action: Actions
|
||||
action: Actions,
|
||||
hidden: Array<string>,
|
||||
items: Array<TabItem>
|
||||
};
|
||||
|
||||
// FIXME React-router would probably be the best route, not home-grown
|
||||
@ -35,64 +37,89 @@ const Components: { [index: string]: React.ComponentType<any> } = {
|
||||
};
|
||||
|
||||
class AddressesApp extends React.PureComponent<Props, State> {
|
||||
state: State = { action: 'edit' };
|
||||
state: State;
|
||||
|
||||
componentDidUpdate () {
|
||||
const { addressAll } = this.props;
|
||||
const { action } = this.state;
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
if (action === 'edit' && hasNoAddresses(addressAll)) {
|
||||
this.selectCreate();
|
||||
const { allAddresses = {}, t } = props;
|
||||
const baseState = Object.keys(allAddresses).length !== 0
|
||||
? AddressesApp.showEditState()
|
||||
: AddressesApp.hideEditState();
|
||||
|
||||
this.state = {
|
||||
...baseState,
|
||||
items: [
|
||||
{
|
||||
name: 'edit',
|
||||
text: t('app.edit', { defaultValue: 'Edit address' })
|
||||
},
|
||||
{
|
||||
name: 'create',
|
||||
text: t('app.create', { defaultValue: 'Add address' })
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
static showEditState () {
|
||||
return {
|
||||
action: 'edit' as Actions,
|
||||
hidden: []
|
||||
};
|
||||
}
|
||||
|
||||
static hideEditState () {
|
||||
return {
|
||||
action: 'create' as Actions,
|
||||
hidden: ['edit']
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps ({ allAddresses = {} }: Props, { hidden }: State) {
|
||||
const hasAddresses = Object.keys(allAddresses).length !== 0;
|
||||
|
||||
if (hidden.length === 0) {
|
||||
return hasAddresses
|
||||
? null
|
||||
: AddressesApp.hideEditState();
|
||||
}
|
||||
|
||||
return hasAddresses
|
||||
? AddressesApp.showEditState()
|
||||
: null;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { addressAll, t } = this.props;
|
||||
const { action } = this.state;
|
||||
const { action, hidden, items } = this.state;
|
||||
const Component = Components[action];
|
||||
const items = [
|
||||
{
|
||||
name: 'edit',
|
||||
text: t('app.edit', { defaultValue: 'Edit address' })
|
||||
},
|
||||
{
|
||||
name: 'create',
|
||||
text: t('app.create', { defaultValue: 'Add address' })
|
||||
}
|
||||
];
|
||||
|
||||
// Do not load Editor tab if no addresses
|
||||
if (hasNoAddresses(addressAll)) {
|
||||
items.splice(0, 1);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className='addresses--App'>
|
||||
<header>
|
||||
<Tabs
|
||||
activeItem={action}
|
||||
hidden={hidden}
|
||||
items={items}
|
||||
onChange={this.onMenuChange}
|
||||
/>
|
||||
</header>
|
||||
<Component onCreateAddress={this.selectEdit} />
|
||||
<Component onCreateAddress={this.activateEdit} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
onMenuChange = (action: Actions) => {
|
||||
private onMenuChange = (action: Actions) => {
|
||||
this.setState({ action });
|
||||
}
|
||||
|
||||
selectCreate = (): void => {
|
||||
this.setState({ action: 'create' });
|
||||
}
|
||||
|
||||
selectEdit = (): void => {
|
||||
this.setState({ action: 'edit' });
|
||||
private activateEdit = (): void => {
|
||||
this.setState(
|
||||
AddressesApp.showEditState()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withObservableBase(
|
||||
addressObservable.subject, { propName: 'addressAll' }
|
||||
addressObservable.subject, { propName: 'allAddresses' }
|
||||
)(translate(AddressesApp));
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
// Copyright 2017-2018 @polkadot/app-accounts authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
let addressesQty: (addressAll?: Array<any>) => number;
|
||||
|
||||
let hasAddresses: (addressAll?: Array<any>) => boolean;
|
||||
|
||||
let hasNoAddresses: (addressAll?: Array<any>) => boolean;
|
||||
|
||||
addressesQty = (addressAll?: Array<any>): number =>
|
||||
hasAddresses(addressAll) && addressAll ? Object.keys(addressAll).length : 0;
|
||||
|
||||
hasAddresses = (addressAll?: Array<any>): boolean =>
|
||||
!hasNoAddresses(addressAll);
|
||||
|
||||
hasNoAddresses = (addressAll?: Array<any>): boolean =>
|
||||
!addressAll || !Object.keys(addressAll).length;
|
||||
|
||||
export {
|
||||
addressesQty,
|
||||
hasAddresses,
|
||||
hasNoAddresses
|
||||
};
|
||||
@ -8,14 +8,15 @@ import React from 'react';
|
||||
|
||||
import classes from './util/classes';
|
||||
|
||||
type Item = {
|
||||
export type TabItem = {
|
||||
name: string,
|
||||
text: React.ReactNode
|
||||
};
|
||||
|
||||
type Props = BareProps & {
|
||||
activeItem: string,
|
||||
items: Array<Item>,
|
||||
hidden?: Array<string>,
|
||||
items: Array<TabItem>,
|
||||
onChange: (name: any) => void
|
||||
};
|
||||
|
||||
@ -34,16 +35,16 @@ export default class Tabs extends React.PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps: Props, prevState: State) {
|
||||
const { activeItem } = this.props;
|
||||
|
||||
if (activeItem !== prevState.active) {
|
||||
this.setState({ active: activeItem });
|
||||
}
|
||||
static getDerivedStateFromProps ({ activeItem }: Props, { active }: State) {
|
||||
return activeItem === active
|
||||
? null
|
||||
: {
|
||||
active: activeItem
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, activeItem, items, style } = this.props;
|
||||
const { className, activeItem, hidden = [], items, style } = this.props;
|
||||
const { active } = this.state;
|
||||
const currentItem = active || activeItem;
|
||||
|
||||
@ -52,15 +53,20 @@ export default class Tabs extends React.PureComponent<Props, State> {
|
||||
className={classes('ui--Menu', 'ui menu tabular', className)}
|
||||
style={style}
|
||||
>
|
||||
{items.map(({ name, text }) => (
|
||||
<a
|
||||
className={classes('item', currentItem === name ? 'active' : '')}
|
||||
key={name}
|
||||
onClick={this.onSelect(name)}
|
||||
>
|
||||
{text}
|
||||
</a>
|
||||
))}
|
||||
{items
|
||||
.filter(({ name }) =>
|
||||
!hidden.includes(name)
|
||||
)
|
||||
.map(({ name, text }) => (
|
||||
<a
|
||||
className={classes('item', currentItem === name ? 'active' : '')}
|
||||
key={name}
|
||||
onClick={this.onSelect(name)}
|
||||
>
|
||||
{text}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user