ghost-portal/packages/app-addresses/src/Editor.js
Jaco Greeff 5f884c4b65
Add utility/toolbox app (#51)
* Upgrades

* Add & use Output component

* Render app in content

* Use update @polkadot/dev-react

* Add app-toolbox

* DRY className concat

* Hashing in place

* Verify signature operational

* Entry updates

* Verification operational

* Final cleanups before PR

* Bump version
2018-05-15 16:58:32 +02:00

235 lines
5.8 KiB
JavaScript

// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { KeyringAddress } from '@polkadot/ui-keyring/types';
import type { I18nProps } from '@polkadot/ui-app/types';
import React from 'react';
import Button from '@polkadot/ui-app/src/Button';
import Input from '@polkadot/ui-app/src/Input';
import InputAddress from '@polkadot/ui-app/src/InputAddress';
import classes from '@polkadot/ui-app/src/util/classes';
import keyring from '@polkadot/ui-keyring/src';
import Address from '@polkadot/app-accounts/src/Address';
import translate from './translate';
type Props = I18nProps & {
onBack: () => void
};
type State = {
currentAddress: KeyringAddress | null,
defaultPublicKey?: Uint8Array,
editedName: string,
isEdited: boolean,
info: KeyringAddress | null
}
class Editor extends React.PureComponent<Props, State> {
state: State;
constructor (props: Props) {
super(props);
const addresses = keyring.getAddresses();
const currentAddress = addresses[addresses.length - 1] || null;
this.state = this.createState(currentAddress);
this.state.defaultPublicKey = currentAddress
? currentAddress.publicKey()
: void 0;
}
render (): React$Node {
const { className, style, t } = this.props;
const { currentAddress, defaultPublicKey, editedName, isEdited } = this.state;
if (!currentAddress) {
return (
<div
className={classes('addresses--Editor', className)}
style={style}
>
{t('editor.none', {
defaultValue: 'There are no saved addresses. Add some first.'
})}
</div>
);
}
const address = currentAddress.address();
return (
<div
className={classes('addresses--Editor', className)}
style={style}
>
<div className='ui--grid'>
<Address
className='shrink'
value={address}
/>
<div className='grow'>
<div className='ui--row'>
<InputAddress
className='full'
defaultValue={defaultPublicKey}
hideAddress
isInput={false}
label={t('editor.select', {
defaultValue: 'edit the selected address'
})}
onChange={this.onChangeAddress}
type='address'
value={address}
/>
</div>
<div className='ui--row'>
<Input
className='full'
label={t('editor.name', {
defaultValue: 'identified by the name'
})}
onChange={this.onChangeName}
value={editedName}
/>
</div>
</div>
</div>
<Button.Group>
<Button
isNegative
onClick={this.onForget}
text={t('editor.forget', {
defaultValue: 'Forget'
})}
/>
<Button.Group.Divider />
<Button
isDisabled={!isEdited}
onClick={this.onDiscard}
text={t('editor.reset', {
defaultValue: 'Reset'
})}
/>
<Button
isDisabled={!isEdited}
isPrimary
onClick={this.onCommit}
text={t('editor.save', {
defaultValue: 'Save'
})}
/>
</Button.Group>
</div>
);
}
createState (currentAddress: KeyringAddress | null): $Shape<State> {
const { name = '' } = currentAddress
? currentAddress.getMeta()
: {};
return {
currentAddress,
editedName: name,
isEdited: false
};
}
nextState (newState?: $Shape<State> = {}): void {
this.setState(
(prevState: State): $Shape<State> => {
let { currentAddress = prevState.currentAddress, editedName = prevState.editedName } = newState;
const previous = prevState.currentAddress || { address: () => null };
let isEdited = false;
if (currentAddress && currentAddress.isValid()) {
if (currentAddress.address() !== previous.address()) {
editedName = currentAddress.getMeta().name || '';
} else if (editedName !== currentAddress.getMeta().name) {
isEdited = true;
}
} else {
editedName = '';
}
return {
currentAddress,
editedName,
isEdited
};
}
);
}
onChangeAddress = (publicKey: Uint8Array): void => {
const currentAddress = keyring.getAddress(publicKey) || null;
this.nextState({
currentAddress
});
}
onChangeName = (editedName: string): void => {
this.nextState({ editedName });
}
onCommit = (): void => {
const { currentAddress, editedName } = this.state;
if (!currentAddress) {
return;
}
keyring.saveAddress(currentAddress.address(), {
name: editedName,
whenEdited: Date.now()
});
this.nextState({});
}
onDiscard = (): void => {
const { currentAddress } = this.state;
if (!currentAddress) {
return;
}
this.nextState({
editedName: currentAddress.getMeta().name
});
}
onForget = (): void => {
const { currentAddress } = this.state;
if (!currentAddress) {
return;
}
const address = currentAddress.address();
const addresses = keyring.getAddresses().filter((item) =>
item.address() !== address
);
const nextAddress = addresses[0] || null;
const defaultPublicKey = nextAddress
? nextAddress.publicKey()
: void 0;
keyring.forgetAddress(address);
this.nextState({
currentAddress: nextAddress,
defaultPublicKey
});
}
}
export default translate(Editor);