Swap Addresses to grid layout (as in accounts) (#1224)
* Swap Addresses to grid layout (as in accounts) * Failsafe in cryptotype * Edit works. Needs to be made generic. * Address overview + create dialog
This commit is contained in:
parent
f3c603ab2e
commit
0eb050c430
@ -29,6 +29,7 @@ type State = {
|
||||
isTransferOpen: boolean
|
||||
};
|
||||
|
||||
// FIXME This is duplicated in app-ddresses
|
||||
const Wrapper = styled.article`
|
||||
position: relative;
|
||||
flex: 1 1;
|
||||
|
||||
183
packages/app-address-book/src/Address.tsx
Normal file
183
packages/app-address-book/src/Address.tsx
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2017-2019 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { KeyringAddress } from '@polkadot/ui-keyring/types';
|
||||
import { ActionStatus } from '@polkadot/ui-app/Status/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AddressInfo, AddressRow, Button } from '@polkadot/ui-app';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
|
||||
import Forgetting from './modals/Forgetting';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
address: string
|
||||
};
|
||||
|
||||
type State = {
|
||||
current: KeyringAddress,
|
||||
isEditable: boolean,
|
||||
isForgetOpen: boolean
|
||||
};
|
||||
|
||||
// FIXME This is duplicated in app-accounts
|
||||
const Wrapper = styled.article`
|
||||
position: relative;
|
||||
flex: 1 1;
|
||||
min-width: 24%;
|
||||
max-width: 24%;
|
||||
justify-content: space-around;
|
||||
|
||||
.accounts--Account-buttons {
|
||||
text-align: right;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.ui--AddressSummary-base {
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.accounts--Account-buttons > button {
|
||||
margin: .2em;
|
||||
}
|
||||
|
||||
@media (max-width: 2060px) {
|
||||
min-width: 32%;
|
||||
max-width: 32%;
|
||||
}
|
||||
|
||||
@media (max-width: 1580px) {
|
||||
min-width: 49%;
|
||||
max-width: 49%;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
class Address extends React.PureComponent<Props> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { address } = this.props;
|
||||
|
||||
this.state = {
|
||||
current: keyring.getAddress(address),
|
||||
isEditable: true,
|
||||
isForgetOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const { address } = this.props;
|
||||
const { isEditable } = this.state;
|
||||
|
||||
return (
|
||||
<Wrapper className='overview--Account'>
|
||||
{this.renderModals()}
|
||||
<AddressRow
|
||||
buttons={this.renderButtons()}
|
||||
isEditable={isEditable}
|
||||
value={address}
|
||||
withBalance={false}
|
||||
withIndex
|
||||
withNonce={false}
|
||||
withTags
|
||||
>
|
||||
<AddressInfo
|
||||
withBalance={{ available: true, free: true, total: true }}
|
||||
withExtended={{ nonce: true }}
|
||||
value={address}
|
||||
/>
|
||||
</AddressRow>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
private renderModals () {
|
||||
const { address } = this.props;
|
||||
const { isForgetOpen, current } = this.state;
|
||||
|
||||
if (!address) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const modals = [];
|
||||
|
||||
if (isForgetOpen) {
|
||||
modals.push(
|
||||
<Forgetting
|
||||
currentAddress={current}
|
||||
doForget={this.onForget}
|
||||
key='modal-forget-account'
|
||||
onClose={this.toggleForget}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return modals;
|
||||
}
|
||||
|
||||
private toggleForget = (): void => {
|
||||
const { isForgetOpen } = this.state;
|
||||
|
||||
this.setState({
|
||||
isForgetOpen: !isForgetOpen
|
||||
});
|
||||
}
|
||||
|
||||
private onForget = (): void => {
|
||||
const { address, t } = this.props;
|
||||
|
||||
if (!address) {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = {
|
||||
account: address,
|
||||
action: 'forget'
|
||||
} as ActionStatus;
|
||||
|
||||
try {
|
||||
keyring.forgetAddress(address);
|
||||
status.status = 'success';
|
||||
status.message = t('address forgotten');
|
||||
} catch (error) {
|
||||
status.status = 'error';
|
||||
status.message = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
private renderButtons () {
|
||||
const { t } = this.props;
|
||||
const { isEditable } = this.state;
|
||||
|
||||
return (
|
||||
<div className='accounts--Account-buttons buttons'>
|
||||
{isEditable && (
|
||||
<>
|
||||
<Button
|
||||
isNegative
|
||||
onClick={this.toggleForget}
|
||||
icon='trash'
|
||||
size='small'
|
||||
tooltip={t('Forget this account')}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Address);
|
||||
@ -1,223 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/app-address-book authors & contributors
|
||||
// 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 { ComponentProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { AddressRow, Button, Input, InputTags, TxComponent } from '@polkadot/ui-app';
|
||||
import { ActionStatus } from '@polkadot/ui-app/Status/types';
|
||||
import { InputAddress } from '@polkadot/ui-app/InputAddress';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ComponentProps & I18nProps;
|
||||
|
||||
type State = {
|
||||
address: string,
|
||||
isAddressExisting: boolean,
|
||||
isAddressValid: boolean,
|
||||
isNameValid: boolean,
|
||||
isValid: boolean,
|
||||
name: string,
|
||||
tags: Array<string>
|
||||
};
|
||||
|
||||
class Creator extends TxComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = this.emptyState();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { address, name } = this.state;
|
||||
|
||||
return (
|
||||
<div className='address-book--Creator'>
|
||||
<div className='ui--grid'>
|
||||
{this.renderInput()}
|
||||
<AddressRow
|
||||
className='shrink'
|
||||
defaultName={name}
|
||||
value={address}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderButtons () {
|
||||
const { t } = this.props;
|
||||
const { isValid } = this.state;
|
||||
|
||||
return (
|
||||
<Button.Group>
|
||||
<Button
|
||||
onClick={this.onDiscard}
|
||||
label={t('Reset')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={this.onCommit}
|
||||
label={t('Save')}
|
||||
ref={this.button}
|
||||
/>
|
||||
</Button.Group>
|
||||
);
|
||||
}
|
||||
|
||||
renderInput () {
|
||||
const { t } = this.props;
|
||||
const { address, isAddressValid, isNameValid, name, tags } = this.state;
|
||||
|
||||
return (
|
||||
<div className='grow'>
|
||||
<div className='ui--row'>
|
||||
<Input
|
||||
autoFocus
|
||||
className='full'
|
||||
help={t('Paste here the address of the contact you want to add to your address book.')}
|
||||
isError={!isAddressValid}
|
||||
label={t('address')}
|
||||
onChange={this.onChangeAddress}
|
||||
onEnter={this.submit}
|
||||
value={address}
|
||||
/>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<Input
|
||||
className='full'
|
||||
help={t('Type the name of your contact. This name will be used across all the apps. It can be edited later on.')}
|
||||
isError={!isNameValid}
|
||||
label={t('name')}
|
||||
onChange={this.onChangeName}
|
||||
onEnter={this.submit}
|
||||
value={name}
|
||||
/>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<InputTags
|
||||
help={t('Additional user-specified tags that can be used to identify the address. Tags can be used for categorization and filtering.')}
|
||||
label={t('user-defined tags')}
|
||||
onChange={this.onChangeTags}
|
||||
value={tags}
|
||||
/>
|
||||
</div>
|
||||
{this.renderButtons()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
emptyState (): State {
|
||||
return {
|
||||
address: '',
|
||||
isAddressExisting: false,
|
||||
isAddressValid: false,
|
||||
isNameValid: true,
|
||||
isValid: false,
|
||||
name: 'new address',
|
||||
tags: []
|
||||
};
|
||||
}
|
||||
|
||||
nextState (newState: State, allowEdit: boolean = false): void {
|
||||
this.setState(
|
||||
(prevState: State): State => {
|
||||
let { address = prevState.address, name = prevState.name, tags = prevState.tags } = newState;
|
||||
let isAddressValid = true;
|
||||
let isAddressExisting = false;
|
||||
let newAddress = address;
|
||||
|
||||
try {
|
||||
newAddress = keyring.encodeAddress(
|
||||
keyring.decodeAddress(address)
|
||||
);
|
||||
isAddressValid = keyring.isAvailable(newAddress);
|
||||
|
||||
if (!isAddressValid) {
|
||||
const old = keyring.getAddress(newAddress);
|
||||
|
||||
if (old.isValid) {
|
||||
if (!allowEdit) {
|
||||
name = old.getMeta().name || name;
|
||||
}
|
||||
|
||||
isAddressExisting = true;
|
||||
isAddressValid = true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
isAddressValid = false;
|
||||
}
|
||||
|
||||
const isNameValid = !!name;
|
||||
|
||||
return {
|
||||
address: newAddress,
|
||||
isAddressExisting,
|
||||
isAddressValid,
|
||||
isNameValid,
|
||||
isValid: isAddressValid && isNameValid,
|
||||
name,
|
||||
tags
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onChangeAddress = (address: string): void => {
|
||||
this.nextState({ address } as State);
|
||||
}
|
||||
|
||||
onChangeName = (name: string): void => {
|
||||
this.nextState({ name } as State, true);
|
||||
}
|
||||
|
||||
onChangeTags = (tags: Array<string>): void => {
|
||||
this.setState({ tags });
|
||||
}
|
||||
|
||||
onCommit = (): void => {
|
||||
const { basePath, onStatusChange, t } = this.props;
|
||||
const { address, isAddressExisting, name, tags } = this.state;
|
||||
|
||||
const status = {
|
||||
action: 'create'
|
||||
} as ActionStatus;
|
||||
|
||||
try {
|
||||
keyring.saveAddress(address, { name, tags });
|
||||
|
||||
status.account = address;
|
||||
status.status = address ? 'success' : 'error';
|
||||
status.message = isAddressExisting
|
||||
? t('address edited')
|
||||
: t('address created');
|
||||
|
||||
InputAddress.setLastValue('address', address);
|
||||
} catch (error) {
|
||||
status.status = 'error';
|
||||
status.message = error.message;
|
||||
}
|
||||
|
||||
onStatusChange(status);
|
||||
|
||||
if (status.status !== 'error') {
|
||||
window.location.hash = basePath;
|
||||
}
|
||||
}
|
||||
|
||||
onDiscard = (): void => {
|
||||
this.setState(this.emptyState());
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Creator);
|
||||
@ -1,284 +0,0 @@
|
||||
// Copyright 2017-2019 @polkadot/app-address-book authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { KeyringAddress } from '@polkadot/ui-keyring/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { AddressRow, Button, Input, InputAddress, InputTags, TxComponent } from '@polkadot/ui-app';
|
||||
import { ActionStatus } from '@polkadot/ui-app/Status/types';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
|
||||
import Forgetting from './Forgetting';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ComponentProps & I18nProps;
|
||||
|
||||
type State = {
|
||||
current: KeyringAddress | null,
|
||||
editedName: string,
|
||||
isEdited: boolean,
|
||||
isForgetOpen: boolean,
|
||||
tags: Array<string>
|
||||
};
|
||||
|
||||
class Editor extends TxComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = this.createState(null);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isForgetOpen, current } = this.state;
|
||||
return (
|
||||
<div className='address-book--Editor'>
|
||||
<Forgetting
|
||||
isOpen={isForgetOpen}
|
||||
onClose={this.toggleForget}
|
||||
doForget={this.onForget}
|
||||
currentAddress={current}
|
||||
/>
|
||||
{this.renderData()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderButtons () {
|
||||
const { t } = this.props;
|
||||
const { current, isEdited } = this.state;
|
||||
|
||||
if (!current) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button.Group>
|
||||
<Button
|
||||
isNegative
|
||||
onClick={this.toggleForget}
|
||||
label={t('Forget')}
|
||||
/>
|
||||
<Button.Group.Divider />
|
||||
<Button
|
||||
isDisabled={!isEdited}
|
||||
onClick={this.onDiscard}
|
||||
label={t('Reset')}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
isDisabled={!isEdited}
|
||||
isPrimary
|
||||
onClick={this.onCommit}
|
||||
label={t('Save')}
|
||||
ref={this.button}
|
||||
/>
|
||||
</Button.Group>
|
||||
);
|
||||
}
|
||||
|
||||
renderData () {
|
||||
const { t } = this.props;
|
||||
const { current, editedName, tags } = this.state;
|
||||
|
||||
const address = current
|
||||
? current.address()
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className='ui--grid'>
|
||||
<div className='grow'>
|
||||
<div className='ui--row'>
|
||||
<InputAddress
|
||||
className='full'
|
||||
help={t('Select the contact you want to edit or forget.')}
|
||||
hideAddress
|
||||
isInput={false}
|
||||
label={t('contact')}
|
||||
onChange={this.onChangeAddress}
|
||||
type='address'
|
||||
value={address}
|
||||
/>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<Input
|
||||
className='full'
|
||||
help={t('Name associated with the selected contact. You can change it here. This name will be changed across all the apps.')}
|
||||
label={t('name')}
|
||||
onChange={this.onChangeName}
|
||||
onEnter={this.submit}
|
||||
value={editedName}
|
||||
/>
|
||||
</div>
|
||||
<div className='ui--row'>
|
||||
<InputTags
|
||||
help={t('Additional user-specified tags that can be used to identify the address. Tags can be used for categorization and filtering.')}
|
||||
label={t('user-defined tags')}
|
||||
onChange={this.onChangeTags}
|
||||
value={tags}
|
||||
/>
|
||||
</div>
|
||||
{this.renderButtons()}
|
||||
</div>
|
||||
<AddressRow
|
||||
className='shrink'
|
||||
value={address || ''}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
createState (current: KeyringAddress | null): State {
|
||||
const meta = current
|
||||
? current.getMeta()
|
||||
: {};
|
||||
|
||||
return {
|
||||
current,
|
||||
editedName: meta.name || '',
|
||||
isEdited: false,
|
||||
isForgetOpen: false,
|
||||
tags: meta.tags || []
|
||||
};
|
||||
}
|
||||
|
||||
nextState (newState: State = {} as State): void {
|
||||
this.setState(
|
||||
(prevState: State): State => {
|
||||
let { current = prevState.current, editedName = prevState.editedName, tags = prevState.tags } = newState;
|
||||
const previous = prevState.current || { address: () => null };
|
||||
let isEdited = false;
|
||||
|
||||
if (current && current.isValid()) {
|
||||
const meta = current.getMeta();
|
||||
|
||||
if (current.address() !== previous.address()) {
|
||||
editedName = meta.name || '';
|
||||
tags = meta.tags || [];
|
||||
} else if (editedName !== meta.name) {
|
||||
isEdited = true;
|
||||
}
|
||||
} else {
|
||||
editedName = '';
|
||||
}
|
||||
|
||||
let isForgetOpen = false;
|
||||
|
||||
return {
|
||||
current,
|
||||
editedName,
|
||||
isEdited,
|
||||
isForgetOpen,
|
||||
tags
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onChangeAddress = (accountId: string): void => {
|
||||
const current = accountId && keyring.decodeAddress(accountId)
|
||||
? (keyring.getAddress(accountId) || null)
|
||||
: null;
|
||||
|
||||
this.nextState({ current } as State);
|
||||
}
|
||||
|
||||
onChangeName = (editedName: string): void => {
|
||||
this.nextState({ editedName } as State);
|
||||
}
|
||||
|
||||
onChangeTags = (tags: Array<string>): void => {
|
||||
this.setState({ isEdited: true, tags });
|
||||
}
|
||||
|
||||
onCommit = (): void => {
|
||||
const { onStatusChange, t } = this.props;
|
||||
const { current, editedName, tags } = this.state;
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = {
|
||||
account: current.address(),
|
||||
action: 'edit'
|
||||
} as ActionStatus;
|
||||
|
||||
try {
|
||||
keyring.saveAddress(current.address(), {
|
||||
name: editedName,
|
||||
tags,
|
||||
whenEdited: Date.now()
|
||||
});
|
||||
|
||||
status.status = current.getMeta().name === editedName ? 'success' : 'error';
|
||||
status.message = t('address edited');
|
||||
} catch (error) {
|
||||
status.status = 'error';
|
||||
status.message = error.message;
|
||||
}
|
||||
|
||||
onStatusChange(status);
|
||||
}
|
||||
|
||||
onDiscard = (): void => {
|
||||
const { current } = this.state;
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const meta = current.getMeta();
|
||||
|
||||
this.nextState({
|
||||
editedName: meta.name,
|
||||
tags: meta.tags || []
|
||||
} as State);
|
||||
}
|
||||
|
||||
toggleForget = (): void => {
|
||||
this.setState(
|
||||
({ isForgetOpen }: State) => ({
|
||||
isForgetOpen: !isForgetOpen
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onForget = (): void => {
|
||||
const { onStatusChange, t } = this.props;
|
||||
const { current } = this.state;
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
this.createState(null),
|
||||
() => {
|
||||
const status = {
|
||||
account: current.address(),
|
||||
action: 'forget'
|
||||
} as ActionStatus;
|
||||
|
||||
try {
|
||||
keyring.forgetAddress(
|
||||
current.address()
|
||||
);
|
||||
status.status = 'success';
|
||||
status.message = t('address forgotten');
|
||||
} catch (error) {
|
||||
status.status = 'error';
|
||||
status.message = error.message;
|
||||
}
|
||||
|
||||
onStatusChange(status);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Editor);
|
||||
88
packages/app-address-book/src/Overview.tsx
Normal file
88
packages/app-address-book/src/Overview.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright 2017-2019 @polkadot/app-address-book authors & contributors
|
||||
// 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 { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { ComponentProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Button } from '@polkadot/ui-app';
|
||||
import addressObservable from '@polkadot/ui-keyring/observable/addresses';
|
||||
import { withMulti, withObservable } from '@polkadot/ui-api';
|
||||
|
||||
import CreateModal from './modals/Create';
|
||||
import Address from './Address';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ComponentProps & I18nProps & {
|
||||
addresses?: SubjectInfo[]
|
||||
};
|
||||
|
||||
type State = {
|
||||
isCreateOpen: boolean
|
||||
};
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.addresses {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.spacer {
|
||||
flex: 1 1;
|
||||
margin: .25rem;
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
class Overview extends React.PureComponent<Props, State> {
|
||||
state: State = {
|
||||
isCreateOpen: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { addresses, onStatusChange, t } = this.props;
|
||||
const { isCreateOpen } = this.state;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Button.Group>
|
||||
<Button
|
||||
isPrimary
|
||||
label={t('Add contact')}
|
||||
onClick={this.toggleCreate}
|
||||
/>
|
||||
</Button.Group>
|
||||
{isCreateOpen && (
|
||||
<CreateModal
|
||||
onClose={this.toggleCreate}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
<div className='addresses'>
|
||||
{addresses && Object.keys(addresses).map((address) => (
|
||||
<Address
|
||||
address={address}
|
||||
key={address}
|
||||
/>
|
||||
))}
|
||||
<div className='spacer' />
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleCreate = (): void => {
|
||||
this.setState(({ isCreateOpen }) => ({
|
||||
isCreateOpen: !isCreateOpen
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Overview,
|
||||
translate,
|
||||
withObservable(addressObservable.subject, { propName: 'addresses' })
|
||||
);
|
||||
@ -16,9 +16,7 @@ import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
|
||||
import { withMulti, withObservable } from '@polkadot/ui-api';
|
||||
|
||||
import basicMd from './md/basic.md';
|
||||
import CreateModal from './modals/Create';
|
||||
import Creator from './Creator';
|
||||
import Editor from './Editor';
|
||||
import Overview from './Overview';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = AppProps & I18nProps & {
|
||||
@ -47,12 +45,8 @@ class AddressBookApp extends React.PureComponent<Props, State> {
|
||||
isCreateOpen: false,
|
||||
items: [
|
||||
{
|
||||
name: 'edit',
|
||||
text: t('Edit contact')
|
||||
},
|
||||
{
|
||||
name: 'create',
|
||||
text: t('Add contact')
|
||||
name: 'overview',
|
||||
text: t('Overview')
|
||||
}
|
||||
]
|
||||
};
|
||||
@ -85,9 +79,8 @@ class AddressBookApp extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { basePath, onStatusChange } = this.props;
|
||||
const { hidden, isCreateOpen, items } = this.state;
|
||||
const renderCreator = this.renderComponent(Creator);
|
||||
const { basePath } = this.props;
|
||||
const { hidden, items } = this.state;
|
||||
|
||||
return (
|
||||
<main className='address-book--App'>
|
||||
@ -100,21 +93,8 @@ class AddressBookApp extends React.PureComponent<Props, State> {
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/create`} render={renderCreator} />
|
||||
<Route
|
||||
render={
|
||||
hidden.includes('edit')
|
||||
? renderCreator
|
||||
: this.renderComponent(Editor)
|
||||
}
|
||||
/>
|
||||
<Route render={this.renderComponent(Overview)} />
|
||||
</Switch>
|
||||
{isCreateOpen && (
|
||||
<CreateModal
|
||||
onClose={this.toggleCreate}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@ -132,12 +112,6 @@ class AddressBookApp extends React.PureComponent<Props, State> {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private toggleCreate = (): void => {
|
||||
this.setState(({ isCreateOpen }) => ({
|
||||
isCreateOpen: !isCreateOpen
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
|
||||
@ -8,10 +8,9 @@ import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import React from 'react';
|
||||
import { AddressRow, Button, Modal } from '@polkadot/ui-app';
|
||||
|
||||
import translate from './translate';
|
||||
import translate from '../translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
isOpen: boolean,
|
||||
onClose: () => void,
|
||||
doForget: () => void,
|
||||
currentAddress: KeyringAddress | null
|
||||
@ -23,11 +22,7 @@ class Forgetting extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isOpen, style } = this.props;
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
const { style, t } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -35,6 +30,7 @@ class Forgetting extends React.PureComponent<Props> {
|
||||
open
|
||||
style={style}
|
||||
>
|
||||
<Modal.Header>{t('Confirm address removal')}</Modal.Header>
|
||||
{this.renderContent()}
|
||||
{this.renderButtons()}
|
||||
</Modal>
|
||||
@ -71,20 +67,15 @@ class Forgetting extends React.PureComponent<Props> {
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal.Header>
|
||||
{t('Confirm address removal')}
|
||||
</Modal.Header>
|
||||
<Modal.Content className='forgetting-Address'>
|
||||
<AddressRow
|
||||
isInline
|
||||
value={address || ''}
|
||||
>
|
||||
<p>{t('You are about to remove this address from your address book. Once completed, should you need to access it again, you will have to re-add the address.')}</p>
|
||||
<p>{t('This operation does not remove the history of the account from the chain, nor any associated funds from the account. The forget operation only limits your access to the address on this browser.')}</p>
|
||||
</AddressRow>
|
||||
</Modal.Content>
|
||||
</>
|
||||
<Modal.Content className='forgetting-Address'>
|
||||
<AddressRow
|
||||
isInline
|
||||
value={address || ''}
|
||||
>
|
||||
<p>{t('You are about to remove this address from your address book. Once completed, should you need to access it again, you will have to re-add the address.')}</p>
|
||||
<p>{t('This operation does not remove the history of the account from the chain, nor any associated funds from the account. The forget operation only limits your access to the address on this browser.')}</p>
|
||||
</AddressRow>
|
||||
</Modal.Content>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ class AddressSummary extends React.PureComponent<Props, State> {
|
||||
hasChanged = true;
|
||||
}
|
||||
|
||||
if (name !== prevState.name) {
|
||||
if (!prevState.isEditingName && name !== prevState.name) {
|
||||
state.name = name;
|
||||
hasChanged = true;
|
||||
}
|
||||
@ -427,48 +427,51 @@ class AddressSummary extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
protected saveName = () => {
|
||||
const { value } = this.props;
|
||||
const { address, name } = this.state;
|
||||
|
||||
const trimmedName = name.trim();
|
||||
const meta = {
|
||||
name: trimmedName,
|
||||
whenEdited: Date.now()
|
||||
};
|
||||
|
||||
// Save only if the name was changed or if it's no empty.
|
||||
if (trimmedName && value) {
|
||||
const currentKeyring = keyring.getPair(address);
|
||||
if (trimmedName && address) {
|
||||
try {
|
||||
const currentKeyring = keyring.getPair(address);
|
||||
|
||||
currentKeyring && keyring.saveAccountMeta(currentKeyring, {
|
||||
name: trimmedName,
|
||||
whenEdited: Date.now()
|
||||
});
|
||||
currentKeyring && keyring.saveAccountMeta(currentKeyring, meta);
|
||||
} catch (error) {
|
||||
keyring.saveAddress(address, meta);
|
||||
}
|
||||
|
||||
this.setState({ isEditingName: false });
|
||||
}
|
||||
}
|
||||
|
||||
protected saveTags = () => {
|
||||
const { value } = this.props;
|
||||
const { address, tags } = this.state;
|
||||
const meta = {
|
||||
tags,
|
||||
whenEdited: Date.now()
|
||||
};
|
||||
|
||||
if (value) {
|
||||
const currentKeyring = keyring.getPair(address);
|
||||
if (address) {
|
||||
try {
|
||||
const currentKeyring = keyring.getPair(address);
|
||||
|
||||
currentKeyring && keyring.saveAccountMeta(currentKeyring, {
|
||||
tags,
|
||||
whenEdited: Date.now()
|
||||
});
|
||||
currentKeyring && keyring.saveAccountMeta(currentKeyring, meta);
|
||||
} catch (error) {
|
||||
keyring.saveAddress(address, meta);
|
||||
}
|
||||
|
||||
this.setState({ isEditingTags: false });
|
||||
}
|
||||
}
|
||||
|
||||
protected toggleNameEditor = () => {
|
||||
const { value } = this.props;
|
||||
|
||||
if (value && keyring.getPair(value.toString())) {
|
||||
this.setState(({ isEditingName }) => ({
|
||||
isEditingName: !isEditingName
|
||||
}));
|
||||
}
|
||||
this.setState(({ isEditingName }) => ({
|
||||
isEditingName: !isEditingName
|
||||
}));
|
||||
}
|
||||
|
||||
protected toggleTagsEditor = () => {
|
||||
|
||||
@ -18,12 +18,19 @@ type Props = BareProps & {
|
||||
export default class CryptoType extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { accountId, className, label = '' } = this.props;
|
||||
const current = accountId
|
||||
let type = '<unknown>';
|
||||
|
||||
try {
|
||||
const current = accountId
|
||||
? keyring.getPair(accountId.toString())
|
||||
: null;
|
||||
const type = current
|
||||
? current.type
|
||||
: 'ed25519';
|
||||
|
||||
if (current) {
|
||||
type = current.type;
|
||||
}
|
||||
} catch (error) {
|
||||
// cannot determine, keep unknown
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes('ui--CryptoType', className)}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user