Skip to content

Commit

Permalink
Implemented manual broadcasting of custom json operations
Browse files Browse the repository at this point in the history
  • Loading branch information
aaroncox committed Nov 19, 2017
1 parent b330641 commit 1f3fafe
Show file tree
Hide file tree
Showing 7 changed files with 292 additions and 1 deletion.
33 changes: 33 additions & 0 deletions app/actions/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { Asset, Price, Client } from 'dsteem'
import type { accountStateType } from '../reducers/account';
import * as ProcessingActions from './processing';

export const ACCOUNT_CUSTOM_JSON_STARTED = 'ACCOUNT_CUSTOM_JSON_STARTED';
export const ACCOUNT_CUSTOM_JSON_RESOLVED = 'ACCOUNT_CUSTOM_JSON_RESOLVED';
export const ACCOUNT_CUSTOM_JSON_FAILED = 'ACCOUNT_CUSTOM_JSON_FAILED';
export const ACCOUNT_CUSTOM_JSON_COMPLETED = 'ACCOUNT_CUSTOM_JSON_COMPLETED';
export const ACCOUNT_DATA_MINIMUM_ACCOUNT_DELEGATION = 'ACCOUNT_DATA_MINIMUM_ACCOUNT_DELEGATION';
export const ACCOUNT_DATA_UPDATE = 'ACCOUNT_DATA_UPDATE';
export const ACCOUNT_DATA_UPDATE_FAILED = 'ACCOUNT_DATA_UPDATE_FAILED';
Expand Down Expand Up @@ -422,3 +426,32 @@ export function cancelWithdrawVesting(wif, params) {
});
};
}

export function customJson(wif, params) {
return (dispatch: () => void) => {
const { account, id, json } = params
dispatch({
type: ACCOUNT_CUSTOM_JSON_STARTED
})
steem.broadcast.customJson(wif, [], [account], id, json, function(err, result) {
if(result) {
dispatch({
type: ACCOUNT_CUSTOM_JSON_RESOLVED
})
}
if(err) {
dispatch({
type: ACCOUNT_CUSTOM_JSON_FAILED,
payload: err
})
}
});
};
}


export function customJsonCompleted() {
return {
type: ACCOUNT_CUSTOM_JSON_COMPLETED,
}
}
142 changes: 142 additions & 0 deletions app/components/Accounts/CustomJSON.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// @flow
import React, { Component } from 'react';
import { Grid, Header, Message, Segment, Select, Table } from 'semantic-ui-react';

import { Form, Input } from 'formsy-semantic-ui-react';

import AccountName from '../global/AccountName';

export default class AccountsCustomJSON extends Component {
constructor(props) {
super(props)
this.state = {
account: props.keys.names[0],
id: '',
json: '',
message: false
}
}

resetState(extraState) {
this.setState(Object.assign({}, {
id: '',
json: ''
}, extraState))
}


handleIdChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
id: value
})
}

handleJsonChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
json: value.trim()
})
}

handleAccountChange = (e: SyntheticEvent, { value }: { value: any }) => {
this.setState({
account: value
})
}

onValidSubmit = (
e: SyntheticEvent
) => {
const { account, id, json } = this.state
this.setState({message: false})
this.props.actions.useKey('customJson', { account, id, json }, this.props.keys.permissions[account]);
}

componentWillReceiveProps = (nextProps) => {
if (nextProps.processing.account_custom_json_resolved) {
nextProps.actions.customJsonCompleted();
this.resetState({
'message': 'Your transaction was successfully broadcast.'
});
}
}

render() {
const {
account_custom_json_error,
account_custom_json_pending,
account_custom_json_resolved
} = this.props.processing;
const keys = this.props.keys;
const availableFrom = keys.names.map((name) => {
const hasPermission = (keys.permissions[name].type === 'active' || keys.permissions[name].type === 'owner');
return hasPermission ? {
key: name,
text: name,
value: name
} : {
key: name,
disabled: true,
text: name + ' (unavailable - active/owner key not loaded)'
};
});
let message = false
if(this.state.message) {
message = (
<Message
success
header="Operation Complete"
content={this.state.message}
/>
)
}
return (
<Segment basic padded>
<Header>
<Header.Subheader>
Broadcast a Custom JSON operation to the Steem blockchain.
</Header.Subheader>
</Header>
{message}
<Form
onValidSubmit={this.onValidSubmit}
error={account_custom_json_error}
loading={account_custom_json_pending}
>
<Form.Field
control={Select}
value={this.state.account}
name="from"
label="Select an account to broadcast with"
options={availableFrom}
placeholder="Sending Account..."
onChange={this.handleAccountChange}
/>
<Form.Input
label="ID"
name="id"
value={this.state.id}
onChange={this.handleIdChange}
placeholder=""
/>
<Form.TextArea
label="JSON"
name="json"
value={this.state.json}
onChange={this.handleJsonChange}
placeholder=""
/>
<Message
error
header="Operation Error"
content={account_custom_json_error}
/>
<Form.Button
color='blue'
content='Broadcast'
disabled={account_custom_json_pending}
/>
</Form>
</Segment>
);
}
}
1 change: 0 additions & 1 deletion app/components/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export default class Settings extends Component {
onValidSubmit = (
e: SyntheticEvent
) => {
console.log(e)
const { setPreference } = this.props.actions;
setPreference('steemd_node', e.steemd_node);
}
Expand Down
83 changes: 83 additions & 0 deletions app/containers/AdvancedPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// @flow
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { Redirect } from 'react-router';
import { connect } from 'react-redux';
import { Button, Header, Icon, Menu, Modal, Segment, Table } from 'semantic-ui-react';

import AccountsCustomJson from '../components/Accounts/CustomJSON.js';
import * as AccountActions from '../actions/account';
import * as KeyActions from '../actions/keys';
import * as ProcessingActions from '../actions/processing';
import MenuBar from './MenuBar';
import ContentBar from '../components/ContentBar';

class AccountsPage extends Component {

state = {
activeItem: 'custom_json'
};

handleItemClick = (e, { name }) => this.setState({ activeItem: name })

render() {
if (!this.props.keys.isUser) {
return <Redirect to="/" />;
}
const { activeItem } = this.state;
let activeTab = <AccountsCustomJson {...this.props} />;
switch (activeItem) {
default: {
activeTab = <AccountsCustomJson {...this.props} />;
break;
}
}
return (
<ContentBar>
<Segment basic padded attached secondary>
<Header>
<Icon name="lab" />
<Header.Content>
Advanced Operations
<Header.Subheader>
This section can be used to perform more advanced operations using the loaded accounts.
</Header.Subheader>
</Header.Content>
</Header>
</Segment>
<Menu tabular attached>
<Menu.Item
name="custom_json"
icon="lock"
content="Custom JSON"
active={activeItem === 'custom_json'}
onClick={this.handleItemClick}
/>
</Menu>
{activeTab}
<MenuBar />
</ContentBar>
);
}
}

function mapStateToProps(state) {
return {
account: state.account,
keys: state.keys,
processing: state.processing,
steem: state.steem
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
...AccountActions,
...KeyActions,
...ProcessingActions,
}, dispatch)
};
}

export default connect(mapStateToProps, mapDispatchToProps)(AccountsPage);
4 changes: 4 additions & 0 deletions app/containers/MenuBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ class MenuBar extends Component {
<Icon name="settings" />
Settings
</Link>
<Link className="link item" to="/advanced">
<Icon name="lab" />
Advanced
</Link>
<Menu.Item
className="link"
style={{
Expand Down
28 changes: 28 additions & 0 deletions app/reducers/processing.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
} from '../actions/processing';

import {
ACCOUNT_CUSTOM_JSON_STARTED,
ACCOUNT_CUSTOM_JSON_RESOLVED,
ACCOUNT_CUSTOM_JSON_FAILED,
ACCOUNT_CUSTOM_JSON_COMPLETED,
ACCOUNT_TRANSFER_STARTED,
ACCOUNT_TRANSFER_FAILED,
ACCOUNT_TRANSFER_RESOLVED,
Expand Down Expand Up @@ -92,6 +96,30 @@ export default function processing(state: any = defaultState, action: actionType
account_transfer_resolved: true,
account_transfer_pending: false
});
case ACCOUNT_CUSTOM_JSON_STARTED:
return Object.assign({}, state, {
account_custom_json_error: false,
account_custom_json_resolved: false,
account_custom_json_pending: true
});
case ACCOUNT_CUSTOM_JSON_FAILED:
return Object.assign({}, state, {
account_custom_json_error: setError(action.payload),
account_custom_json_resolved: false,
account_custom_json_pending: false
});
case ACCOUNT_CUSTOM_JSON_RESOLVED:
return Object.assign({}, state, {
account_custom_json_error: false,
account_custom_json_resolved: true,
account_custom_json_pending: false
});
case ACCOUNT_CUSTOM_JSON_COMPLETED:
return Object.assign({}, state, {
account_custom_json_error: false,
account_custom_json_resolved: false,
account_custom_json_pending: false
});
case ACCOUNT_TRANSFER_COMPLETED:
return Object.assign({}, state, {
account_transfer_error: false,
Expand Down
2 changes: 2 additions & 0 deletions app/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Switch, Route } from 'react-router';
import steem from 'steem';

import App from './containers/App';
import AdvancedPage from './containers/AdvancedPage';
import AccountsPage from './containers/AccountsPage';
import DebugPage from './containers/DebugPage';
import SettingsPage from './containers/SettingsPage';
Expand Down Expand Up @@ -74,6 +75,7 @@ class Routes extends Component {
<Route path="/vesting" component={VestingPage} />
<Route path="/accounts" component={AccountsPage} />
<Route path="/settings" component={SettingsPage} />
<Route path="/advanced" component={AdvancedPage} />
</Switch>
</App>
);
Expand Down

0 comments on commit 1f3fafe

Please sign in to comment.