Initial new UI source code import (#2607)
* address -> name mappings * expanding, loading all coin details * send use only actual BasicCoin tokens registered (any reg) * sending token & accounts * form styling updates * send form layout in place * coin send working as expected * api subscriptions on multiple addresses * bring in events * simplify * basic events display in-place, functionally complete * basic functionality in-place * fix horrible event address issue * rwork display of events slightly * test TLA availability * table for owner -> tokens * fix signature lookup address * fix signature lookup address * basic overview styling * txhash links * page layout adjustments * background import * adjust colors * no global registration, simplify color selection * updated styling * connection dialog for "busy connecting" * initial token connection - WIP * init token updates take place * basic test for manual token * rework connection display * allow updates of the secure token * first stab at making the build build * update runner tags * fix linting issues * skip tests requiring network (should be e2e, TODO) * re-enable javascript tag/runner * release push does the trick * push to any branch, CI name * javscript-test runner as well * swap dependencies build requires test * revert stages swap * retrieve images associated with tokens * remove js build deps order * null image when hash = 0x0 * 6x64 images (hashes for registries) * don't pass tokens as prop to IdentityIcon * check images against content hash pictures * cleanup signer after connection changes * fix naming typo * display unknownImages for balances (not available as content hash) * unknownImage for transfer dialog * basic githubhint layout * single input for commit/filename * ethcore_hashContent call * lookup hash * registration in place * fixes * events is using a proper table * pass value through as-is * stop wrongly using main app IdentityIcon * NEVER export class instance functions * alignment back to normal * typo in definition * set & get images working (mostly) * show content retrieval info * set exitcode via || * use javascript:latest images * disable npm progress bar * rename phase I * rename phase II * only send build output to GitHub on major branches * also run the build step as part of the test (until comprehensive) * ci-specific build (no webpack progress) * allow for account creation via recovery phrase * display account uuid (where available), closes #2546 * connection dialog now shows up in dapps as well, closes #2538 * token images show up as expected * IdentityName component added and deployed * fix padding tests * adjust tests to map to stricter 0x-prefixed hex * render names via common component for the address -> name * split lint into seperate script (early exit) * test phases changed to lint, test & pack * pack part of test phase * remove files marked for deletion (cleanup) * Signer cleanups, start moving in the direction of the rest * add personal signer methods * basic signer request subscription * don't poll blockNumber when not connected * missing return, creating massive ws queue backlogs * ΞTH -> ETH * fix failing tests * registry uses setAddress to actually set addresses now * bytes mapping operates on lowerCase hex strings * sha3 ids for each application * add dappreg to list of contracts * adjust alignment of queries * show gas estimation log * abi with payable for register function * add key as required * image retrieval from dappreg * use proper Image urls * embed and link apps from Parity, retrieved via /api/apps * filter apps that has been replaced * proxy entry for parity-utils * add basiccoin abi * add support for fallback abi type * capture constructor paramaters * merge master into js * move images to assets/images/ * add font assets * import fonts as part of build * don't inline woff files * Revert "merge master into js" This reverts commit cfcfa81bd26f1b3cbc748d3afa1eb5c670b363fe. * remove unused npm packages * information on gas estimates (like almost everywhere else) * don't pass gas & gasPrice to estimation * display account passwordhint when available * signer subscriptions based on polling & function trapping * pending requests retrieved via jsapi * update signer middleware * remove all web3 instances * remove web3 package * last web3 dependencies removed * no need to toChecksumAddress - api takes care of it * expand description for personal_confirmRequest * Signer conversion from web3 -> parity.js completed * explicit in no return * green circle background * remove generated background * convert /api/* paths to localhost:8080/api/* paths (hard-coded, temporary) * change dapps to load from localhost:8080/ui/* * remove dangling web3 files * update manager test for signer * /api/ping -> / * additional token images * additional token images * add missing styles.css for 8180 error pages * cater for txhash returning null/empty object * adjust output directories * Release merge with origin with ours strategy * additional token images * cater for development server * s/localhost/127.0.0.1/ (cater for origin) * Fix address selection for contract deployment * Adjust z-index for error overlay * better text on unique background pattern * fix signer rejections * Don't allow gavcoin transfer with no balance * fix txhash rendering in signer * remove unnecessary ParityBackground * script to update js-precompiled * Redirect from :8080 to :8180 * Remove extra return * Dapp logo images
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.account-selector {
|
||||
}
|
||||
|
||||
.avatar > img {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { List, ListItem } from 'material-ui/List';
|
||||
import Subheader from 'material-ui/Subheader';
|
||||
import Avatar from 'material-ui/Avatar';
|
||||
|
||||
import IdentityIcon from '../../IdentityIcon';
|
||||
|
||||
import styles from './account-selector.css';
|
||||
|
||||
class AccountSelectorItem extends Component {
|
||||
|
||||
static propTypes = {
|
||||
onSelectAccount: PropTypes.func.isRequired,
|
||||
account: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const account = this.props.account;
|
||||
|
||||
const props = Object.assign({}, this.props);
|
||||
delete props.account;
|
||||
delete props.onSelectAccount;
|
||||
|
||||
const icon = (<IdentityIcon
|
||||
inline center
|
||||
address={ account.address } />
|
||||
);
|
||||
|
||||
const avatar = (<Avatar
|
||||
className={ styles.avatar }
|
||||
backgroundColor='none'
|
||||
icon={ icon } />
|
||||
);
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
onClick={ this.onSelectAccount }
|
||||
value={ account.address }
|
||||
primaryText={ account.name }
|
||||
secondaryText={ account.address }
|
||||
leftAvatar={ avatar }
|
||||
{ ...props } />
|
||||
);
|
||||
}
|
||||
|
||||
onSelectAccount = () => {
|
||||
this.props.onSelectAccount(this.props.account.address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default class AccountSelector extends Component {
|
||||
|
||||
static propTypes = {
|
||||
list: PropTypes.array.isRequired,
|
||||
selected: PropTypes.object.isRequired,
|
||||
handleSetSelected: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
state = {
|
||||
open: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const nestedAccounts = this.renderAccounts(this.props.list);
|
||||
const selectedAccount = (
|
||||
<AccountSelectorItem
|
||||
account={ this.props.selected }
|
||||
nestedItems={ nestedAccounts }
|
||||
open={ this.state.open }
|
||||
onSelectAccount={ this.onToggleOpen }
|
||||
autoGenerateNestedIndicator={ false } />
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={ styles['account-selector'] }>
|
||||
<List>
|
||||
<Subheader>Select an account</Subheader>
|
||||
{ selectedAccount }
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderAccounts (accounts) {
|
||||
return accounts
|
||||
.map((account, index) => (
|
||||
<AccountSelectorItem
|
||||
account={ account }
|
||||
onSelectAccount={ this.onSelectAccount }
|
||||
key={ index } />
|
||||
));
|
||||
}
|
||||
|
||||
onToggleOpen = () => {
|
||||
this.setState({ open: !this.state.open });
|
||||
}
|
||||
|
||||
onSelectAccount = (address) => {
|
||||
this.props.handleSetSelected(address);
|
||||
this.onToggleOpen();
|
||||
}
|
||||
|
||||
}
|
||||
45
js/src/dapps/tokenreg/Accounts/AccountSelector/container.js
Normal file
45
js/src/dapps/tokenreg/Accounts/AccountSelector/container.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import AccountSelector from './account-selector';
|
||||
|
||||
import { setSelectedAccount } from '../actions';
|
||||
|
||||
class AccountSelectorContainer extends Component {
|
||||
render () {
|
||||
return (<AccountSelector
|
||||
{ ...this.props }
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { accounts } = state;
|
||||
return { ...accounts };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
handleSetSelected: (address) => {
|
||||
dispatch(setSelectedAccount(address));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountSelectorContainer);
|
||||
17
js/src/dapps/tokenreg/Accounts/AccountSelector/index.js
Normal file
17
js/src/dapps/tokenreg/Accounts/AccountSelector/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './container';
|
||||
61
js/src/dapps/tokenreg/Accounts/actions.js
Normal file
61
js/src/dapps/tokenreg/Accounts/actions.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const { api } = window.parity;
|
||||
|
||||
export const SET_ACCOUNTS = 'SET_ACCOUNTS';
|
||||
export const setAccounts = (accounts) => ({
|
||||
type: SET_ACCOUNTS,
|
||||
accounts
|
||||
});
|
||||
|
||||
export const SET_ACCOUNTS_INFO = 'SET_ACCOUNTS_INFO';
|
||||
export const setAccountsInfo = (accountsInfo) => ({
|
||||
type: SET_ACCOUNTS_INFO,
|
||||
accountsInfo
|
||||
});
|
||||
|
||||
export const SET_SELECTED_ACCOUNT = 'SET_SELECTED_ACCOUNT';
|
||||
export const setSelectedAccount = (address) => ({
|
||||
type: SET_SELECTED_ACCOUNT,
|
||||
address
|
||||
});
|
||||
|
||||
export const loadAccounts = () => (dispatch) => {
|
||||
Promise
|
||||
.all([
|
||||
api.personal.listAccounts(),
|
||||
api.personal.accountsInfo()
|
||||
])
|
||||
.then(results => {
|
||||
const [ accounts, accountsInfo ] = results;
|
||||
|
||||
const accountsList = accounts
|
||||
.map(address => ({
|
||||
...accountsInfo[address],
|
||||
address
|
||||
}));
|
||||
|
||||
console.log('accounts', accountsList);
|
||||
|
||||
dispatch(setAccounts(accountsList));
|
||||
dispatch(setAccountsInfo(accountsInfo));
|
||||
dispatch(setSelectedAccount(accountsList[0].address));
|
||||
})
|
||||
.catch(e => {
|
||||
console.error('loadAccounts error', e);
|
||||
});
|
||||
};
|
||||
57
js/src/dapps/tokenreg/Accounts/reducer.js
Normal file
57
js/src/dapps/tokenreg/Accounts/reducer.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {
|
||||
SET_ACCOUNTS,
|
||||
SET_SELECTED_ACCOUNT,
|
||||
SET_ACCOUNTS_INFO
|
||||
} from './actions';
|
||||
|
||||
const initialState = {
|
||||
list: [],
|
||||
accountsInfo: {},
|
||||
selected: null
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case SET_ACCOUNTS:
|
||||
return {
|
||||
...state,
|
||||
list: [].concat(action.accounts)
|
||||
};
|
||||
|
||||
case SET_ACCOUNTS_INFO:
|
||||
return {
|
||||
...state,
|
||||
accountsInfo: { ...action.accountsInfo }
|
||||
};
|
||||
|
||||
case SET_SELECTED_ACCOUNT: {
|
||||
const address = action.address;
|
||||
const account = state.list.find(a => a.address === address);
|
||||
|
||||
return {
|
||||
...state,
|
||||
selected: account
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
17
js/src/dapps/tokenreg/Actions/Query/index.js
Normal file
17
js/src/dapps/tokenreg/Actions/Query/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './query';
|
||||
207
js/src/dapps/tokenreg/Actions/Query/query.js
Normal file
207
js/src/dapps/tokenreg/Actions/Query/query.js
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { Dialog, FlatButton, SelectField, MenuItem } from 'material-ui';
|
||||
|
||||
import InputText from '../../Inputs/Text';
|
||||
import Loading from '../../Loading';
|
||||
import Token from '../../Tokens/Token';
|
||||
|
||||
import { SIMPLE_TOKEN_ADDRESS_TYPE, SIMPLE_TLA_TYPE } from '../../Inputs/validation';
|
||||
|
||||
import styles from '../actions.css';
|
||||
|
||||
const initState = {
|
||||
queryKey: 'tla',
|
||||
form: {
|
||||
valid: false,
|
||||
value: ''
|
||||
}
|
||||
};
|
||||
|
||||
export default class QueryAction extends Component {
|
||||
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
|
||||
onClose: PropTypes.func.isRequired,
|
||||
handleQueryToken: PropTypes.func.isRequired,
|
||||
handleQueryMetaLookup: PropTypes.func.isRequired,
|
||||
|
||||
data: PropTypes.object,
|
||||
notFound: PropTypes.bool,
|
||||
metaLoading: PropTypes.bool,
|
||||
metaData: PropTypes.object
|
||||
}
|
||||
|
||||
state = initState;
|
||||
|
||||
render () {
|
||||
return (
|
||||
<Dialog
|
||||
title={ 'search for a token' }
|
||||
open={ this.props.show }
|
||||
className={ styles.dialog }
|
||||
onRequestClose={ this.onClose }
|
||||
actions={ this.renderActions() } >
|
||||
{ this.renderContent() }
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { loading, data, notFound } = this.props;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<FlatButton
|
||||
label='Loading...'
|
||||
primary
|
||||
disabled />
|
||||
);
|
||||
}
|
||||
|
||||
const complete = data || notFound;
|
||||
|
||||
if (complete) {
|
||||
return ([
|
||||
<FlatButton
|
||||
label='Close'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />
|
||||
]);
|
||||
}
|
||||
|
||||
const isValid = this.state.form.valid;
|
||||
|
||||
return ([
|
||||
<FlatButton
|
||||
label='Cancel'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />,
|
||||
<FlatButton
|
||||
label='Query'
|
||||
primary
|
||||
disabled={ !isValid }
|
||||
onTouchTap={ this.onQuery } />
|
||||
]);
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
const { loading, notFound, data } = this.props;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Loading size={ 1 } />
|
||||
);
|
||||
}
|
||||
|
||||
if (notFound) {
|
||||
return (
|
||||
<p>No token has been found in the registry...</p>
|
||||
);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
return this.renderData();
|
||||
}
|
||||
|
||||
return this.renderForm();
|
||||
}
|
||||
|
||||
renderData () {
|
||||
const { data } = this.props;
|
||||
|
||||
return (
|
||||
<Token
|
||||
fullWidth
|
||||
handleMetaLookup={ this.props.handleQueryMetaLookup }
|
||||
isMetaLoading={ this.props.metaLoading }
|
||||
meta={ this.props.metaData }
|
||||
{ ...data }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
return (
|
||||
<div>
|
||||
<SelectField
|
||||
floatingLabelText='Select which field to query'
|
||||
fullWidth
|
||||
value={ this.state.queryKey }
|
||||
onChange={ this.onQueryKeyChange }>
|
||||
<MenuItem value='tla' label='TLA' primaryText='TLA' />
|
||||
<MenuItem value='address' label='Address' primaryText='Address' />
|
||||
</SelectField>
|
||||
|
||||
{
|
||||
this.state.queryKey !== 'tla'
|
||||
? (<InputText
|
||||
key={ 0 }
|
||||
|
||||
floatingLabelText="Token's address"
|
||||
hintText='0xdeadbeef...'
|
||||
|
||||
validationType={ SIMPLE_TOKEN_ADDRESS_TYPE }
|
||||
onChange={ this.onChange }
|
||||
onEnter={ this.onQuery } />)
|
||||
: (<InputText
|
||||
key={ 1 }
|
||||
|
||||
floatingLabelText="Token's TLA"
|
||||
hintText='GAV'
|
||||
|
||||
validationType={ SIMPLE_TLA_TYPE }
|
||||
onChange={ this.onChange }
|
||||
onEnter={ this.onQuery } />)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onQueryKeyChange = (event, index, queryKey) => {
|
||||
this.setState({
|
||||
queryKey,
|
||||
form: { valid: false, value: '' }
|
||||
});
|
||||
}
|
||||
|
||||
onChange = (valid, value) => {
|
||||
this.setState({
|
||||
form: {
|
||||
valid, value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onQuery = () => {
|
||||
if (!this.state.form.valid) return;
|
||||
|
||||
const { queryKey, form } = this.state;
|
||||
|
||||
this.props.handleQueryToken(queryKey, form.value);
|
||||
}
|
||||
|
||||
onClose = () => {
|
||||
this.setState(initState);
|
||||
this.props.onClose();
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/dapps/tokenreg/Actions/Register/index.js
Normal file
17
js/src/dapps/tokenreg/Actions/Register/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './register';
|
||||
217
js/src/dapps/tokenreg/Actions/Register/register.js
Normal file
217
js/src/dapps/tokenreg/Actions/Register/register.js
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { Dialog, FlatButton } from 'material-ui';
|
||||
|
||||
import AccountSelector from '../../Accounts/AccountSelector';
|
||||
import InputText from '../../Inputs/Text';
|
||||
|
||||
import { TOKEN_ADDRESS_TYPE, TLA_TYPE, UINT_TYPE, STRING_TYPE } from '../../Inputs/validation';
|
||||
|
||||
import styles from '../actions.css';
|
||||
|
||||
const defaultField = { value: '', valid: false };
|
||||
const initState = {
|
||||
isFormValid: false,
|
||||
fields: {
|
||||
address: {
|
||||
...defaultField,
|
||||
type: TOKEN_ADDRESS_TYPE,
|
||||
floatingLabelText: 'Token address',
|
||||
hintText: 'The token address'
|
||||
},
|
||||
tla: {
|
||||
...defaultField,
|
||||
type: TLA_TYPE,
|
||||
floatingLabelText: 'Token TLA',
|
||||
hintText: 'The token short name (3 characters)'
|
||||
},
|
||||
base: {
|
||||
...defaultField,
|
||||
type: UINT_TYPE,
|
||||
floatingLabelText: 'Token Base',
|
||||
hintText: 'The token precision'
|
||||
},
|
||||
name: {
|
||||
...defaultField,
|
||||
type: STRING_TYPE,
|
||||
floatingLabelText: 'Token name',
|
||||
hintText: 'The token name'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default class RegisterAction extends Component {
|
||||
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
sending: PropTypes.bool.isRequired,
|
||||
complete: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
handleRegisterToken: PropTypes.func.isRequired,
|
||||
|
||||
error: PropTypes.object
|
||||
}
|
||||
|
||||
state = initState;
|
||||
|
||||
render () {
|
||||
const { sending, error, complete } = this.props;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
title={ error ? 'error' : 'register a new token' }
|
||||
open={ this.props.show }
|
||||
modal={ sending || complete }
|
||||
className={ styles.dialog }
|
||||
onRequestClose={ this.onClose }
|
||||
actions={ this.renderActions() } >
|
||||
{ this.renderContent() }
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { complete, sending, error } = this.props;
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<FlatButton
|
||||
label='Close'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />
|
||||
);
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
return (
|
||||
<FlatButton
|
||||
label='Done'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />
|
||||
);
|
||||
}
|
||||
|
||||
const isValid = this.state.isFormValid;
|
||||
|
||||
return ([
|
||||
<FlatButton
|
||||
label='Cancel'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />,
|
||||
<FlatButton
|
||||
label={ sending ? 'Sending...' : 'Register' }
|
||||
primary
|
||||
disabled={ !isValid || sending }
|
||||
onTouchTap={ this.onRegister } />
|
||||
]);
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
const { error, complete } = this.props;
|
||||
|
||||
if (error) return this.renderError();
|
||||
if (complete) return this.renderComplete();
|
||||
return this.renderForm();
|
||||
}
|
||||
|
||||
renderError () {
|
||||
const { error } = this.props;
|
||||
|
||||
return (<div>
|
||||
<p className={ styles.error }>{ error.toString() }</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderComplete () {
|
||||
return (<div>
|
||||
<p>Your transaction has been posted. Please visit the Parity Signer to authenticate the transfer.</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
return (
|
||||
<div>
|
||||
<AccountSelector />
|
||||
{ this.renderInputs() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputs () {
|
||||
const { fields } = this.state;
|
||||
|
||||
return Object.keys(fields).map((fieldKey, index) => {
|
||||
const onChange = this.onChange.bind(this, fieldKey);
|
||||
const field = fields[fieldKey];
|
||||
|
||||
return (
|
||||
<InputText
|
||||
key={ index }
|
||||
|
||||
floatingLabelText={ field.floatingLabelText }
|
||||
hintText={ field.hintText }
|
||||
|
||||
validationType={ field.type }
|
||||
onChange={ onChange } />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onChange (fieldKey, valid, value) {
|
||||
const { fields } = this.state;
|
||||
const field = fields[fieldKey];
|
||||
|
||||
const newFields = {
|
||||
...fields,
|
||||
[ fieldKey ]: {
|
||||
...field,
|
||||
valid, value
|
||||
}
|
||||
};
|
||||
|
||||
const isFormValid = Object.keys(newFields)
|
||||
.map(key => newFields[key].valid)
|
||||
.reduce((current, fieldValid) => {
|
||||
return current && fieldValid;
|
||||
}, true);
|
||||
|
||||
this.setState({
|
||||
fields: newFields,
|
||||
isFormValid
|
||||
});
|
||||
}
|
||||
|
||||
onRegister = () => {
|
||||
const { fields } = this.state;
|
||||
|
||||
const data = Object.keys(fields)
|
||||
.reduce((dataObject, fieldKey) => {
|
||||
dataObject[fieldKey] = fields[fieldKey].value;
|
||||
return dataObject;
|
||||
}, {});
|
||||
|
||||
this.props.handleRegisterToken(data);
|
||||
}
|
||||
|
||||
onClose = () => {
|
||||
this.setState(initState);
|
||||
this.props.onClose();
|
||||
}
|
||||
|
||||
}
|
||||
50
js/src/dapps/tokenreg/Actions/actions.css
Normal file
50
js/src/dapps/tokenreg/Actions/actions.css
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.actions {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
.button button {
|
||||
background-color: #27ae60 !important;
|
||||
height: 56px !important;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
.button button[disabled] {
|
||||
background-color: rgba(50, 50, 50, 0.25) !important;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
}
|
||||
|
||||
.dialog h3 {
|
||||
color: rgba(50, 100, 150, 1) !important;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.dialogtext {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
215
js/src/dapps/tokenreg/Actions/actions.js
Normal file
215
js/src/dapps/tokenreg/Actions/actions.js
Normal file
@@ -0,0 +1,215 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { getTokenTotalSupply } from '../utils';
|
||||
|
||||
const { sha3, bytesToHex } = window.parity.api.util;
|
||||
|
||||
export const SET_REGISTER_SENDING = 'SET_REGISTER_SENDING';
|
||||
export const setRegisterSending = (isSending) => ({
|
||||
type: SET_REGISTER_SENDING,
|
||||
isSending
|
||||
});
|
||||
|
||||
export const SET_REGISTER_ERROR = 'SET_REGISTER_ERROR';
|
||||
export const setRegisterError = (e) => ({
|
||||
type: SET_REGISTER_ERROR,
|
||||
error: e
|
||||
});
|
||||
|
||||
export const REGISTER_RESET = 'REGISTER_RESET';
|
||||
export const registerReset = () => ({
|
||||
type: REGISTER_RESET
|
||||
});
|
||||
|
||||
export const REGISTER_COMPLETED = 'REGISTER_COMPLETED';
|
||||
export const registerCompleted = () => ({
|
||||
type: REGISTER_COMPLETED
|
||||
});
|
||||
|
||||
export const registerToken = (tokenData) => (dispatch, getState) => {
|
||||
console.log('registering token', tokenData);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
const fee = state.status.contract.fee;
|
||||
|
||||
const { address, base, name, tla } = tokenData;
|
||||
|
||||
dispatch(setRegisterSending(true));
|
||||
|
||||
const values = [ address, tla, base, name ];
|
||||
const options = {
|
||||
from: state.accounts.selected.address,
|
||||
value: fee
|
||||
};
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
return contractInstance
|
||||
.fromTLA.call({}, [ tla ])
|
||||
.then(([id, address, base, name, owner]) => {
|
||||
if (owner !== '0x0000000000000000000000000000000000000000') {
|
||||
throw new Error(`A Token has already been registered with the TLA ${tla}`);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
return contractInstance
|
||||
.fromAddress.call({}, [ address ])
|
||||
.then(([id, tla, base, name, owner]) => {
|
||||
if (owner !== '0x0000000000000000000000000000000000000000') {
|
||||
throw new Error(`A Token has already been registered with the Address ${address}`);
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
return contractInstance
|
||||
.register.estimateGas(options, values);
|
||||
})
|
||||
.then((gasEstimate) => {
|
||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||
console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
|
||||
|
||||
return contractInstance.register.postTransaction(options, values);
|
||||
})
|
||||
.then((result) => {
|
||||
dispatch(registerCompleted());
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('registerToken error', e);
|
||||
dispatch(setRegisterError(e));
|
||||
});
|
||||
};
|
||||
|
||||
export const SET_QUERY_LOADING = 'SET_QUERY_LOADING';
|
||||
export const setQueryLoading = (isLoading) => ({
|
||||
type: SET_QUERY_LOADING,
|
||||
isLoading
|
||||
});
|
||||
|
||||
export const SET_QUERY_RESULT = 'SET_QUERY_RESULT';
|
||||
export const setQueryResult = (data) => ({
|
||||
type: SET_QUERY_RESULT,
|
||||
data
|
||||
});
|
||||
|
||||
export const SET_QUERY_NOT_FOUND = 'SET_QUERY_NOT_FOUND';
|
||||
export const setQueryNotFound = () => ({
|
||||
type: SET_QUERY_NOT_FOUND
|
||||
});
|
||||
|
||||
export const QUERY_RESET = 'QUERY_RESET';
|
||||
export const queryReset = () => ({
|
||||
type: QUERY_RESET
|
||||
});
|
||||
|
||||
export const SET_QUERY_META_LOADING = 'SET_QUERY_META_LOADING';
|
||||
export const setQueryMetaLoading = (isLoading) => ({
|
||||
type: SET_QUERY_META_LOADING,
|
||||
isLoading
|
||||
});
|
||||
|
||||
export const SET_QUERY_META = 'SET_QUERY_META';
|
||||
export const setQueryMeta = (data) => ({
|
||||
type: SET_QUERY_META,
|
||||
data
|
||||
});
|
||||
|
||||
export const queryToken = (key, query) => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
const contractFunc = (key === 'tla') ? 'fromTLA' : 'fromAddress';
|
||||
|
||||
dispatch(setQueryLoading(true));
|
||||
|
||||
contractInstance[contractFunc]
|
||||
.call({}, [ query ])
|
||||
.then((result) => {
|
||||
const data = {
|
||||
index: result[0].toNumber(),
|
||||
base: result[2].toNumber(),
|
||||
name: result[3],
|
||||
owner: result[4]
|
||||
};
|
||||
|
||||
if (key === 'tla') {
|
||||
data.tla = query;
|
||||
data.address = result[1];
|
||||
}
|
||||
|
||||
if (key === 'address') {
|
||||
data.address = query;
|
||||
data.tla = result[1];
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
.then(data => {
|
||||
return getTokenTotalSupply(data.address)
|
||||
.then(totalSupply => {
|
||||
data.totalSupply = totalSupply;
|
||||
return data;
|
||||
});
|
||||
})
|
||||
.then(data => {
|
||||
if (data.totalSupply === null) {
|
||||
dispatch(setQueryNotFound());
|
||||
dispatch(setQueryLoading(false));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
data.totalSupply = data.totalSupply.toNumber();
|
||||
dispatch(setQueryResult(data));
|
||||
dispatch(setQueryLoading(false));
|
||||
}, () => {
|
||||
dispatch(setQueryNotFound());
|
||||
dispatch(setQueryLoading(false));
|
||||
});
|
||||
};
|
||||
|
||||
export const queryTokenMeta = (id, query) => (dispatch, getState) => {
|
||||
console.log('loading token meta', query);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
const key = sha3(query);
|
||||
|
||||
const startDate = Date.now();
|
||||
dispatch(setQueryMetaLoading(true));
|
||||
|
||||
contractInstance
|
||||
.meta
|
||||
.call({}, [ id, key ])
|
||||
.then((value) => {
|
||||
const meta = {
|
||||
key, query,
|
||||
value: value.find(v => v !== 0) ? bytesToHex(value) : null
|
||||
};
|
||||
|
||||
dispatch(setQueryMeta(meta));
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch(setQueryMetaLoading(false));
|
||||
}, 500 - (Date.now() - startDate));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('load meta query error', e);
|
||||
});
|
||||
};
|
||||
119
js/src/dapps/tokenreg/Actions/component.js
Normal file
119
js/src/dapps/tokenreg/Actions/component.js
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { RaisedButton } from 'material-ui';
|
||||
import ActionSearchIcon from 'material-ui/svg-icons/action/search';
|
||||
import ContentSendIcon from 'material-ui/svg-icons/content/send';
|
||||
|
||||
import Register from './Register';
|
||||
import Query from './Query';
|
||||
|
||||
import styles from './actions.css';
|
||||
|
||||
const REGISTER_ACTION = 'REGISTER_ACTION';
|
||||
const QUERY_ACTION = 'QUERY_ACTION';
|
||||
|
||||
export default class Actions extends Component {
|
||||
|
||||
static propTypes = {
|
||||
handleRegisterToken: PropTypes.func.isRequired,
|
||||
handleRegisterClose: PropTypes.func.isRequired,
|
||||
register: PropTypes.object.isRequired,
|
||||
|
||||
handleQueryToken: PropTypes.func.isRequired,
|
||||
handleQueryClose: PropTypes.func.isRequired,
|
||||
handleQueryMetaLookup: PropTypes.func.isRequired,
|
||||
query: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
state = {
|
||||
show: {
|
||||
[ REGISTER_ACTION ]: false,
|
||||
[ QUERY_ACTION ]: false
|
||||
}
|
||||
}
|
||||
|
||||
constructor () {
|
||||
super();
|
||||
|
||||
this.onShowRegister = this.onShow.bind(this, REGISTER_ACTION);
|
||||
this.onShowQuery = this.onShow.bind(this, QUERY_ACTION);
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className={ styles.actions }>
|
||||
<RaisedButton
|
||||
className={ styles.button }
|
||||
icon={ <ContentSendIcon /> }
|
||||
label='Register Token'
|
||||
primary
|
||||
onTouchTap={ this.onShowRegister } />
|
||||
|
||||
<RaisedButton
|
||||
className={ styles.button }
|
||||
icon={ <ActionSearchIcon /> }
|
||||
label='Search Token'
|
||||
primary
|
||||
onTouchTap={ this.onShowQuery } />
|
||||
|
||||
<Register
|
||||
show={ this.state.show[ REGISTER_ACTION ] }
|
||||
onClose={ this.onRegisterClose }
|
||||
handleRegisterToken={ this.props.handleRegisterToken }
|
||||
{ ...this.props.register } />
|
||||
|
||||
<Query
|
||||
show={ this.state.show[ QUERY_ACTION ] }
|
||||
onClose={ this.onQueryClose }
|
||||
handleQueryToken={ this.props.handleQueryToken }
|
||||
handleQueryMetaLookup={ this.props.handleQueryMetaLookup }
|
||||
{ ...this.props.query } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onRegisterClose = () => {
|
||||
this.onHide(REGISTER_ACTION);
|
||||
this.props.handleRegisterClose();
|
||||
}
|
||||
|
||||
onQueryClose = () => {
|
||||
this.onHide(QUERY_ACTION);
|
||||
this.props.handleQueryClose();
|
||||
}
|
||||
|
||||
onShow (key) {
|
||||
this.setState({
|
||||
show: {
|
||||
...this.state.show,
|
||||
[ key ]: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onHide (key) {
|
||||
this.setState({
|
||||
show: {
|
||||
...this.state.show,
|
||||
[ key ]: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
62
js/src/dapps/tokenreg/Actions/container.js
Normal file
62
js/src/dapps/tokenreg/Actions/container.js
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Actions from './component';
|
||||
|
||||
import { registerToken, registerReset, queryToken, queryReset, queryTokenMeta } from './actions';
|
||||
|
||||
class TokensContainer extends Component {
|
||||
|
||||
render () {
|
||||
return (<Actions
|
||||
{ ...this.props }
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { register, query } = state.actions;
|
||||
|
||||
return { register, query };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
handleRegisterToken: (tokenData) => {
|
||||
dispatch(registerToken(tokenData));
|
||||
},
|
||||
handleRegisterClose: () => {
|
||||
dispatch(registerReset());
|
||||
},
|
||||
handleQueryToken: (key, query) => {
|
||||
dispatch(queryToken(key, query));
|
||||
},
|
||||
handleQueryClose: () => {
|
||||
dispatch(queryReset());
|
||||
},
|
||||
handleQueryMetaLookup: (id, query) => {
|
||||
dispatch(queryTokenMeta(id, query));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TokensContainer);
|
||||
17
js/src/dapps/tokenreg/Actions/index.js
Normal file
17
js/src/dapps/tokenreg/Actions/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './container.js';
|
||||
155
js/src/dapps/tokenreg/Actions/reducer.js
Normal file
155
js/src/dapps/tokenreg/Actions/reducer.js
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {
|
||||
SET_REGISTER_SENDING,
|
||||
SET_REGISTER_ERROR,
|
||||
REGISTER_RESET,
|
||||
REGISTER_COMPLETED,
|
||||
|
||||
SET_QUERY_LOADING,
|
||||
SET_QUERY_RESULT,
|
||||
SET_QUERY_NOT_FOUND,
|
||||
SET_QUERY_META_LOADING,
|
||||
SET_QUERY_META,
|
||||
QUERY_RESET
|
||||
} from './actions';
|
||||
|
||||
const initialState = {
|
||||
register: {
|
||||
sending: false,
|
||||
error: null,
|
||||
complete: false
|
||||
},
|
||||
query: {
|
||||
loading: false,
|
||||
data: null,
|
||||
notFound: false,
|
||||
metaLoading: false,
|
||||
metaData: null
|
||||
}
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case SET_REGISTER_SENDING: {
|
||||
const registerState = state.register;
|
||||
|
||||
return {
|
||||
...state,
|
||||
register: {
|
||||
...registerState,
|
||||
sending: action.isSending
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case REGISTER_COMPLETED: {
|
||||
const registerState = state.register;
|
||||
|
||||
return {
|
||||
...state,
|
||||
register: {
|
||||
...registerState,
|
||||
sending: false,
|
||||
complete: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_REGISTER_ERROR: {
|
||||
const registerState = state.register;
|
||||
|
||||
return {
|
||||
...state,
|
||||
register: {
|
||||
...registerState,
|
||||
sending: false,
|
||||
error: action.error
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case REGISTER_RESET: {
|
||||
return {
|
||||
...state,
|
||||
register: initialState.register
|
||||
};
|
||||
}
|
||||
|
||||
case SET_QUERY_LOADING: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...state.query,
|
||||
loading: action.isLoading
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_QUERY_RESULT: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...state.query,
|
||||
data: action.data
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_QUERY_NOT_FOUND: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...state.query,
|
||||
notFound: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_QUERY_META_LOADING: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...state.query,
|
||||
metaLoading: action.isLoading
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case SET_QUERY_META: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...state.query,
|
||||
metaData: action.data
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
case QUERY_RESET: {
|
||||
return {
|
||||
...state,
|
||||
query: {
|
||||
...initialState.query
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
22
js/src/dapps/tokenreg/Application/application.css
Normal file
22
js/src/dapps/tokenreg/Application/application.css
Normal file
@@ -0,0 +1,22 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.application {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
72
js/src/dapps/tokenreg/Application/application.js
Normal file
72
js/src/dapps/tokenreg/Application/application.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import getMuiTheme from 'material-ui/styles/getMuiTheme';
|
||||
|
||||
import Loading from '../Loading';
|
||||
import Status from '../Status';
|
||||
import Tokens from '../Tokens';
|
||||
import Actions from '../Actions';
|
||||
|
||||
import styles from './application.css';
|
||||
|
||||
const muiTheme = getMuiTheme({
|
||||
palette: {
|
||||
primary1Color: '#27ae60'
|
||||
}
|
||||
});
|
||||
|
||||
export default class Application extends Component {
|
||||
static childContextTypes = {
|
||||
muiTheme: PropTypes.object
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
|
||||
contract: PropTypes.object
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isLoading, contract } = this.props;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Loading />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.application }>
|
||||
<Status
|
||||
address={ contract.address }
|
||||
fee={ contract.fee } />
|
||||
|
||||
<Actions />
|
||||
|
||||
<Tokens />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getChildContext () {
|
||||
return {
|
||||
muiTheme
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/dapps/tokenreg/Application/index.js
Normal file
17
js/src/dapps/tokenreg/Application/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './application';
|
||||
45
js/src/dapps/tokenreg/Chip/chip.css
Normal file
45
js/src/dapps/tokenreg/Chip/chip.css
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.chip > span {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.chip img {
|
||||
margin-bottom: -11px;
|
||||
margin-left: -11px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-family: 'Roboto Mono', monospace;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
-webkit-user-select: text;
|
||||
cursor: text;
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
margin-left: 1em;
|
||||
margin-right: 0.5em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
68
js/src/dapps/tokenreg/Chip/chip.js
Normal file
68
js/src/dapps/tokenreg/Chip/chip.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { Chip } from 'material-ui';
|
||||
|
||||
import IdentityIcon from '../IdentityIcon' ;
|
||||
|
||||
import styles from './chip.css';
|
||||
|
||||
export default class CustomChip extends Component {
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
|
||||
isAddress: PropTypes.bool,
|
||||
displayValue: PropTypes.string
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isAddress, value, label } = this.props;
|
||||
|
||||
const displayValue = this.props.displayValue || value;
|
||||
|
||||
return (
|
||||
<Chip
|
||||
className={ styles.chip }
|
||||
style={ {
|
||||
margin: '0.5em',
|
||||
background: '#27ae60',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
} }>
|
||||
{ this.renderIcon(isAddress, value) }
|
||||
<span className={ styles.value } title={ value }>
|
||||
{ displayValue }
|
||||
</span>
|
||||
<span className={ styles.label }>
|
||||
{ label }
|
||||
</span>
|
||||
</Chip>
|
||||
);
|
||||
}
|
||||
|
||||
renderIcon (isAddress, address) {
|
||||
if (!isAddress) return;
|
||||
|
||||
return (
|
||||
<IdentityIcon
|
||||
inline center
|
||||
address={ address } />
|
||||
);
|
||||
}
|
||||
}
|
||||
17
js/src/dapps/tokenreg/Chip/index.js
Normal file
17
js/src/dapps/tokenreg/Chip/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './chip';
|
||||
64
js/src/dapps/tokenreg/Container.js
Normal file
64
js/src/dapps/tokenreg/Container.js
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Application from './Application';
|
||||
|
||||
import { loadContract } from './Status/actions';
|
||||
import { loadAccounts } from './Accounts/actions';
|
||||
|
||||
class Container extends Component {
|
||||
static propTypes = {
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
contract: PropTypes.object.isRequired,
|
||||
onLoad: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.props.onLoad();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isLoading, contract } = this.props;
|
||||
|
||||
return (<Application
|
||||
isLoading={ isLoading }
|
||||
contract={ contract }
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { isLoading, contract } = state.status;
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
contract
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
onLoad: () => {
|
||||
dispatch(loadContract());
|
||||
dispatch(loadAccounts());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Container);
|
||||
23
js/src/dapps/tokenreg/IdentityIcon/identityIcon.css
Normal file
23
js/src/dapps/tokenreg/IdentityIcon/identityIcon.css
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
36
js/src/dapps/tokenreg/IdentityIcon/identityIcon.js
Normal file
36
js/src/dapps/tokenreg/IdentityIcon/identityIcon.js
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { api } from '../parity';
|
||||
import styles from './identityIcon.css';
|
||||
|
||||
export default class IdentityIcon extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { address } = this.props;
|
||||
|
||||
return (
|
||||
<img
|
||||
className={ styles.icon }
|
||||
src={ api.util.createIdentityImg(address, 4) } />
|
||||
);
|
||||
}
|
||||
}
|
||||
17
js/src/dapps/tokenreg/IdentityIcon/index.js
Normal file
17
js/src/dapps/tokenreg/IdentityIcon/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './identityIcon';
|
||||
37
js/src/dapps/tokenreg/Inputs/Text/container.js
Normal file
37
js/src/dapps/tokenreg/Inputs/Text/container.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import InputText from './input-text';
|
||||
|
||||
class InputTextContainer extends Component {
|
||||
|
||||
render () {
|
||||
return (<InputText
|
||||
{ ...this.props }
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { contract } = state.status;
|
||||
|
||||
return { contract };
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(InputTextContainer);
|
||||
17
js/src/dapps/tokenreg/Inputs/Text/index.js
Normal file
17
js/src/dapps/tokenreg/Inputs/Text/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './container';
|
||||
141
js/src/dapps/tokenreg/Inputs/Text/input-text.js
Normal file
141
js/src/dapps/tokenreg/Inputs/Text/input-text.js
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { TextField } from 'material-ui';
|
||||
import CheckIcon from 'material-ui/svg-icons/navigation/check';
|
||||
import { green500 } from 'material-ui/styles/colors';
|
||||
|
||||
import Loading from '../../Loading';
|
||||
|
||||
import { validate } from '../validation';
|
||||
|
||||
import styles from '../inputs.css';
|
||||
|
||||
const initState = {
|
||||
error: null,
|
||||
value: '',
|
||||
valid: false,
|
||||
disabled: false,
|
||||
loading: false
|
||||
};
|
||||
|
||||
export default class InputText extends Component {
|
||||
|
||||
static propTypes = {
|
||||
validationType: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onEnter: PropTypes.func,
|
||||
|
||||
floatingLabelText: PropTypes.string,
|
||||
hintText: PropTypes.string,
|
||||
|
||||
contract: PropTypes.object
|
||||
}
|
||||
|
||||
state = initState;
|
||||
|
||||
render () {
|
||||
const { disabled, error } = this.state;
|
||||
|
||||
return (
|
||||
<div className={ styles['input-container'] }>
|
||||
<TextField
|
||||
floatingLabelText={ this.props.floatingLabelText }
|
||||
hintText={ this.props.hintText }
|
||||
|
||||
autoComplete='off'
|
||||
floatingLabelFixed
|
||||
fullWidth
|
||||
disabled={ disabled }
|
||||
errorText={ error }
|
||||
onChange={ this.onChange }
|
||||
onKeyDown={ this.onKeyDown } />
|
||||
|
||||
{ this.renderLoading() }
|
||||
{ this.renderIsValid() }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderLoading () {
|
||||
if (!this.state.loading) return;
|
||||
|
||||
return (
|
||||
<div className={ styles['input-loading'] }>
|
||||
<Loading size={ 0.3 } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderIsValid () {
|
||||
if (this.state.loading || !this.state.valid) return;
|
||||
|
||||
return (
|
||||
<div className={ styles['input-icon'] }>
|
||||
<CheckIcon color={ green500 } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onChange = (event) => {
|
||||
const value = event.target.value;
|
||||
// So we can focus on the input after async validation
|
||||
event.persist();
|
||||
|
||||
const { validationType, contract } = this.props;
|
||||
|
||||
const validation = validate(value, validationType, contract);
|
||||
|
||||
if (validation instanceof Promise) {
|
||||
this.setState({ disabled: true, loading: true });
|
||||
|
||||
return validation
|
||||
.then(validation => {
|
||||
this.setValidation({
|
||||
...validation,
|
||||
disabled: false,
|
||||
loading: false
|
||||
});
|
||||
|
||||
event.target.focus();
|
||||
});
|
||||
}
|
||||
|
||||
this.setValidation(validation);
|
||||
}
|
||||
|
||||
onKeyDown = (event) => {
|
||||
if (!this.props.onEnter) return;
|
||||
if (event.keyCode !== 13) return;
|
||||
|
||||
this.props.onEnter();
|
||||
}
|
||||
|
||||
setValidation = (validation) => {
|
||||
const { value } = validation;
|
||||
|
||||
this.setState({ ...validation });
|
||||
|
||||
if (validation.valid) {
|
||||
return this.props.onChange(true, value);
|
||||
}
|
||||
|
||||
return this.props.onChange(false, value);
|
||||
}
|
||||
|
||||
}
|
||||
33
js/src/dapps/tokenreg/Inputs/inputs.css
Normal file
33
js/src/dapps/tokenreg/Inputs/inputs.css
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.input-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input-loading {
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 10px;
|
||||
}
|
||||
212
js/src/dapps/tokenreg/Inputs/validation.js
Normal file
212
js/src/dapps/tokenreg/Inputs/validation.js
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import isURL from 'validator/lib/isURL';
|
||||
|
||||
import { api } from '../parity';
|
||||
|
||||
import { getTokenTotalSupply } from '../utils';
|
||||
|
||||
const {
|
||||
isHex,
|
||||
isAddressValid,
|
||||
toChecksumAddress
|
||||
} = api.util;
|
||||
|
||||
export const ADDRESS_TYPE = 'ADDRESS_TYPE';
|
||||
export const TOKEN_ADDRESS_TYPE = 'TOKEN_ADDRESS_TYPE';
|
||||
export const SIMPLE_TOKEN_ADDRESS_TYPE = 'SIMPLE_TOKEN_ADDRESS_TYPE';
|
||||
export const TLA_TYPE = 'TLA_TYPE';
|
||||
export const SIMPLE_TLA_TYPE = 'SIMPLE_TLA_TYPE';
|
||||
export const UINT_TYPE = 'UINT_TYPE';
|
||||
export const STRING_TYPE = 'STRING_TYPE';
|
||||
export const HEX_TYPE = 'HEX_TYPE';
|
||||
export const URL_TYPE = 'URL_TYPE';
|
||||
|
||||
export const ERRORS = {
|
||||
invalidTLA: 'The TLA should be 3 characters long',
|
||||
invalidUint: 'Please enter a non-negative integer',
|
||||
invalidString: 'Please enter at least a character',
|
||||
invalidAccount: 'Please select an account to transact with',
|
||||
invalidRecipient: 'Please select an account to send to',
|
||||
invalidAddress: 'The address is not in the correct format',
|
||||
invalidTokenAddress: 'The address is not a regular token contract address',
|
||||
invalidHex: 'Please enter an hexadecimal string (digits and letters from a to z)',
|
||||
invalidAmount: 'Please enter a positive amount > 0',
|
||||
invalidTotal: 'The amount is greater than the availale balance',
|
||||
tlaAlreadyTaken: 'This TLA address is already registered',
|
||||
addressAlreadyTaken: 'This Token address is already registered',
|
||||
invalidURL: 'Please enter a valid URL'
|
||||
};
|
||||
|
||||
const validateAddress = (address) => {
|
||||
if (!isAddressValid(address)) {
|
||||
return {
|
||||
error: ERRORS.invalidAddress,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: toChecksumAddress(address),
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
};
|
||||
|
||||
const validateTokenAddress = (address, contract, simple) => {
|
||||
const addressValidation = validateAddress(address);
|
||||
if (!addressValidation.valid) return addressValidation;
|
||||
|
||||
if (simple) return addressValidation;
|
||||
|
||||
return getTokenTotalSupply(address)
|
||||
.then(balance => {
|
||||
if (balance === null) {
|
||||
return {
|
||||
error: ERRORS.invalidTokenAddress,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return contract.instance
|
||||
.fromAddress.call({}, [ address ])
|
||||
.then(([id, tla, base, name, owner]) => {
|
||||
if (owner !== '0x0000000000000000000000000000000000000000') {
|
||||
return {
|
||||
error: ERRORS.addressAlreadyTaken,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
});
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) return result;
|
||||
return addressValidation;
|
||||
});
|
||||
};
|
||||
|
||||
const validateTLA = (tla, contract, simple) => {
|
||||
if (tla.toString().length !== 3) {
|
||||
return {
|
||||
error: ERRORS.invalidTLA,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
const fTLA = tla.toString().toUpperCase();
|
||||
|
||||
if (simple) {
|
||||
return {
|
||||
value: fTLA,
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
}
|
||||
|
||||
return contract.instance
|
||||
.fromTLA.call({}, [ fTLA ])
|
||||
.then(([id, address, base, name, owner]) => {
|
||||
if (owner !== '0x0000000000000000000000000000000000000000') {
|
||||
return {
|
||||
error: ERRORS.tlaAlreadyTaken,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) return result;
|
||||
return {
|
||||
value: fTLA,
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const validateUint = (uint) => {
|
||||
if (!/^\d+$/.test(uint) || parseInt(uint) <= 0) {
|
||||
return {
|
||||
error: ERRORS.invalidUint,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: parseInt(uint),
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
};
|
||||
|
||||
const validateString = (string) => {
|
||||
if (string.toString().length === 0) {
|
||||
return {
|
||||
error: ERRORS.invalidString,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: string.toString(),
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
};
|
||||
|
||||
const validateHex = (string) => {
|
||||
if (!isHex(string.toString())) {
|
||||
return {
|
||||
error: ERRORS.invalidHex,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: string.toString(),
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
};
|
||||
|
||||
const validateURL = (string) => {
|
||||
if (!isURL(string.toString())) {
|
||||
return {
|
||||
error: ERRORS.invalidURL,
|
||||
valid: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
value: string.toString(),
|
||||
error: null,
|
||||
valid: true
|
||||
};
|
||||
};
|
||||
|
||||
export const validate = (value, type, contract) => {
|
||||
if (type === ADDRESS_TYPE) return validateAddress(value);
|
||||
if (type === TOKEN_ADDRESS_TYPE) return validateTokenAddress(value, contract);
|
||||
if (type === SIMPLE_TOKEN_ADDRESS_TYPE) return validateTokenAddress(value, contract, true);
|
||||
if (type === TLA_TYPE) return validateTLA(value, contract);
|
||||
if (type === SIMPLE_TLA_TYPE) return validateTLA(value, contract, true);
|
||||
if (type === UINT_TYPE) return validateUint(value);
|
||||
if (type === STRING_TYPE) return validateString(value);
|
||||
if (type === HEX_TYPE) return validateHex(value);
|
||||
if (type === URL_TYPE) return validateURL(value);
|
||||
|
||||
return { valid: true, error: null };
|
||||
};
|
||||
17
js/src/dapps/tokenreg/Loading/index.js
Normal file
17
js/src/dapps/tokenreg/Loading/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './loading';
|
||||
23
js/src/dapps/tokenreg/Loading/loading.css
Normal file
23
js/src/dapps/tokenreg/Loading/loading.css
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.loading {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
34
js/src/dapps/tokenreg/Loading/loading.js
Normal file
34
js/src/dapps/tokenreg/Loading/loading.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import CircularProgress from 'material-ui/CircularProgress';
|
||||
|
||||
import styles from './loading.css';
|
||||
|
||||
export default class Loading extends Component {
|
||||
static propTypes = {
|
||||
size: PropTypes.number
|
||||
};
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className={ styles.loading }>
|
||||
<CircularProgress size={ this.props.size || 2 } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
202
js/src/dapps/tokenreg/Status/actions.js
Normal file
202
js/src/dapps/tokenreg/Status/actions.js
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {
|
||||
registry as registryAbi,
|
||||
tokenreg as tokenregAbi,
|
||||
githubhint as githubhintAbi
|
||||
} from '../../../contracts/abi';
|
||||
|
||||
import { loadToken, setTokenPending, deleteToken, setTokenData } from '../Tokens/actions';
|
||||
|
||||
const { api } = window.parity;
|
||||
|
||||
export const SET_LOADING = 'SET_LOADING';
|
||||
export const setLoading = (isLoading) => ({
|
||||
type: SET_LOADING,
|
||||
isLoading
|
||||
});
|
||||
|
||||
export const FIND_CONTRACT = 'FIND_CONTRACT';
|
||||
export const loadContract = () => (dispatch) => {
|
||||
dispatch(setLoading(true));
|
||||
|
||||
api.ethcore
|
||||
.registryAddress()
|
||||
.then((registryAddress) => {
|
||||
console.log(`registry found at ${registryAddress}`);
|
||||
const registry = api.newContract(registryAbi, registryAddress).instance;
|
||||
|
||||
return Promise.all([
|
||||
registry.getAddress.call({}, [api.util.sha3('tokenreg'), 'A']),
|
||||
registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A'])
|
||||
]);
|
||||
})
|
||||
.then(([ tokenregAddress, githubhintAddress ]) => {
|
||||
console.log(`tokenreg was found at ${tokenregAddress}`);
|
||||
|
||||
const tokenregContract = api
|
||||
.newContract(tokenregAbi, tokenregAddress);
|
||||
|
||||
const githubhintContract = api
|
||||
.newContract(githubhintAbi, githubhintAddress);
|
||||
|
||||
dispatch(setContractDetails({
|
||||
address: tokenregAddress,
|
||||
instance: tokenregContract.instance,
|
||||
raw: tokenregContract
|
||||
}));
|
||||
|
||||
dispatch(setGithubhintDetails({
|
||||
address: githubhintAddress,
|
||||
instance: githubhintContract.instance,
|
||||
raw: githubhintContract
|
||||
}));
|
||||
|
||||
dispatch(loadContractDetails());
|
||||
dispatch(subscribeEvents());
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('loadContract error', error);
|
||||
});
|
||||
};
|
||||
|
||||
export const LOAD_CONTRACT_DETAILS = 'LOAD_CONTRACT_DETAILS';
|
||||
export const loadContractDetails = () => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
||||
const instance = state.status.contract.instance;
|
||||
|
||||
Promise
|
||||
.all([
|
||||
api.personal.listAccounts(),
|
||||
instance.owner.call(),
|
||||
instance.fee.call()
|
||||
])
|
||||
.then(([accounts, owner, fee]) => {
|
||||
console.log(`owner as ${owner}, fee set at ${fee.toFormat()}`);
|
||||
|
||||
const isOwner = accounts.filter(a => a === owner).length > 0;
|
||||
|
||||
dispatch(setContractDetails({
|
||||
fee,
|
||||
owner,
|
||||
isOwner
|
||||
}));
|
||||
|
||||
dispatch(setLoading(false));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('loadContractDetails error', error);
|
||||
});
|
||||
};
|
||||
|
||||
export const SET_CONTRACT_DETAILS = 'SET_CONTRACT_DETAILS';
|
||||
export const setContractDetails = (details) => ({
|
||||
type: SET_CONTRACT_DETAILS,
|
||||
details
|
||||
});
|
||||
|
||||
export const SET_GITHUBHINT_CONTRACT = 'SET_GITHUBHINT_CONTRACT';
|
||||
export const setGithubhintDetails = (details) => ({
|
||||
type: SET_GITHUBHINT_CONTRACT,
|
||||
details
|
||||
});
|
||||
|
||||
export const subscribeEvents = () => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
||||
const contract = state.status.contract.raw;
|
||||
const previousSubscriptionId = state.status.subscriptionId;
|
||||
|
||||
if (previousSubscriptionId) {
|
||||
contract.unsubscribe(previousSubscriptionId);
|
||||
}
|
||||
|
||||
contract
|
||||
.subscribe(null, {
|
||||
fromBlock: 'latest',
|
||||
toBlock: 'pending',
|
||||
limit: 50
|
||||
}, (error, logs) => {
|
||||
if (error) {
|
||||
console.error('setupFilters', error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!logs || logs.length === 0) return;
|
||||
|
||||
logs.forEach(log => {
|
||||
const event = log.event;
|
||||
const type = log.type;
|
||||
const params = log.params;
|
||||
|
||||
if (event === 'Registered' && type === 'pending') {
|
||||
return dispatch(setTokenData(params.id.toNumber(), {
|
||||
tla: '...',
|
||||
base: -1,
|
||||
address: params.addr,
|
||||
name: params.name,
|
||||
isPending: true
|
||||
}));
|
||||
}
|
||||
|
||||
if (event === 'Registered' && type === 'mined') {
|
||||
return dispatch(loadToken(params.id.toNumber()));
|
||||
}
|
||||
|
||||
if (event === 'Unregistered' && type === 'pending') {
|
||||
return dispatch(setTokenPending(params.id.toNumber(), true));
|
||||
}
|
||||
|
||||
if (event === 'Unregistered' && type === 'mined') {
|
||||
return dispatch(deleteToken(params.id.toNumber()));
|
||||
}
|
||||
|
||||
if (event === 'MetaChanged' && type === 'pending') {
|
||||
return dispatch(setTokenData(
|
||||
params.id.toNumber(),
|
||||
{ metaPending: true, metaMined: false }
|
||||
));
|
||||
}
|
||||
|
||||
if (event === 'MetaChanged' && type === 'mined') {
|
||||
setTimeout(() => {
|
||||
dispatch(setTokenData(
|
||||
params.id.toNumber(),
|
||||
{ metaPending: false, metaMined: false }
|
||||
));
|
||||
}, 5000);
|
||||
|
||||
return dispatch(setTokenData(
|
||||
params.id.toNumber(),
|
||||
{ metaPending: false, metaMined: true }
|
||||
));
|
||||
}
|
||||
|
||||
console.log('new log event', log);
|
||||
});
|
||||
})
|
||||
.then((subscriptionId) => {
|
||||
dispatch(setSubscriptionId(subscriptionId));
|
||||
});
|
||||
};
|
||||
|
||||
export const SET_SUBSCRIPTION_ID = 'SET_SUBSCRIPTION_ID';
|
||||
export const setSubscriptionId = subscriptionId => ({
|
||||
type: SET_SUBSCRIPTION_ID,
|
||||
subscriptionId
|
||||
});
|
||||
17
js/src/dapps/tokenreg/Status/index.js
Normal file
17
js/src/dapps/tokenreg/Status/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './status';
|
||||
65
js/src/dapps/tokenreg/Status/reducer.js
Normal file
65
js/src/dapps/tokenreg/Status/reducer.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {
|
||||
SET_LOADING,
|
||||
SET_CONTRACT_DETAILS,
|
||||
SET_GITHUBHINT_CONTRACT,
|
||||
SET_SUBSCRIPTION_ID
|
||||
} from './actions';
|
||||
|
||||
const initialState = {
|
||||
isLoading: true,
|
||||
subscriptionId: null,
|
||||
contract: {
|
||||
addres: null,
|
||||
instance: null,
|
||||
raw: null,
|
||||
owner: null,
|
||||
isOwner: false,
|
||||
fee: null
|
||||
},
|
||||
githubhint: {
|
||||
address: null,
|
||||
instance: null,
|
||||
raw: null
|
||||
}
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case SET_LOADING:
|
||||
return { ...state, isLoading: action.isLoading };
|
||||
|
||||
case SET_SUBSCRIPTION_ID:
|
||||
return { ...state, subscriptionId: action.subscriptionId };
|
||||
|
||||
case SET_CONTRACT_DETAILS:
|
||||
return { ...state, contract: {
|
||||
...state.contract,
|
||||
...action.details
|
||||
} };
|
||||
|
||||
case SET_GITHUBHINT_CONTRACT:
|
||||
return { ...state, githubhint: {
|
||||
...state.githubhint,
|
||||
...action.details
|
||||
} };
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
36
js/src/dapps/tokenreg/Status/status.css
Normal file
36
js/src/dapps/tokenreg/Status/status.css
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.status {
|
||||
background: rgba(46, 204, 113, 0.85);
|
||||
color: rgba(255, 255, 255, 1);
|
||||
padding: 4em 0 2em 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 3rem;
|
||||
font-weight: 300;
|
||||
margin-top: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
50
js/src/dapps/tokenreg/Status/status.js
Normal file
50
js/src/dapps/tokenreg/Status/status.js
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import Chip from '../Chip';
|
||||
|
||||
import styles from './status.css';
|
||||
|
||||
const { api } = window.parity;
|
||||
|
||||
export default class Status extends Component {
|
||||
static propTypes = {
|
||||
address: PropTypes.string.isRequired,
|
||||
fee: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
render () {
|
||||
const { address, fee } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ styles.status }>
|
||||
<h1 className={ styles.title }>Token Registry</h1>
|
||||
|
||||
<Chip
|
||||
isAddress
|
||||
value={ address }
|
||||
label='Address' />
|
||||
|
||||
<Chip
|
||||
isAddress={ false }
|
||||
value={ api.util.fromWei(fee).toFixed(3) + 'ETH' }
|
||||
label='Fee' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
193
js/src/dapps/tokenreg/Tokens/Token/add-meta.js
Normal file
193
js/src/dapps/tokenreg/Tokens/Token/add-meta.js
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { Dialog, RaisedButton, FlatButton, SelectField, MenuItem } from 'material-ui';
|
||||
import AddIcon from 'material-ui/svg-icons/content/add';
|
||||
|
||||
import InputText from '../../Inputs/Text';
|
||||
import { ADDRESS_TYPE } from '../../Inputs/validation';
|
||||
|
||||
import styles from './token.css';
|
||||
|
||||
import { metaDataKeys } from '../../constants';
|
||||
|
||||
const initState = {
|
||||
showDialog: false,
|
||||
complete: false,
|
||||
metaKeyIndex: 0,
|
||||
|
||||
form: {
|
||||
valid: false,
|
||||
value: ''
|
||||
}
|
||||
};
|
||||
|
||||
export default class AddMeta extends Component {
|
||||
static propTypes = {
|
||||
isTokenOwner: PropTypes.bool,
|
||||
handleAddMeta: PropTypes.func,
|
||||
index: PropTypes.number
|
||||
};
|
||||
|
||||
state = initState;
|
||||
|
||||
render () {
|
||||
if (!this.props.isTokenOwner) return null;
|
||||
|
||||
return (<div className={ styles['add-meta'] }>
|
||||
<RaisedButton
|
||||
label='Add Meta-Data'
|
||||
icon={ <AddIcon /> }
|
||||
primary
|
||||
fullWidth
|
||||
onTouchTap={ this.onShowDialog } />
|
||||
|
||||
<Dialog
|
||||
title='add meta data'
|
||||
open={ this.state.showDialog }
|
||||
modal={ this.state.complete }
|
||||
className={ styles.dialog }
|
||||
onRequestClose={ this.onClose }
|
||||
actions={ this.renderActions() } >
|
||||
{ this.renderContent() }
|
||||
</Dialog>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderActions () {
|
||||
const { complete } = this.state;
|
||||
|
||||
if (complete) {
|
||||
return (
|
||||
<FlatButton
|
||||
label='Done'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />
|
||||
);
|
||||
}
|
||||
|
||||
const isValid = this.state.form.valid;
|
||||
|
||||
return ([
|
||||
<FlatButton
|
||||
label='Cancel'
|
||||
primary
|
||||
onTouchTap={ this.onClose } />,
|
||||
<FlatButton
|
||||
label='Add'
|
||||
primary
|
||||
disabled={ !isValid }
|
||||
onTouchTap={ this.onAdd } />
|
||||
]);
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
const { complete } = this.state;
|
||||
|
||||
if (complete) return this.renderComplete();
|
||||
return this.renderForm();
|
||||
}
|
||||
|
||||
renderComplete () {
|
||||
if (metaDataKeys[this.state.metaKeyIndex].value === 'IMG') {
|
||||
return (<div>
|
||||
<p>
|
||||
Your transactions has been posted.
|
||||
Two transactions are needed to add an Image.
|
||||
Please visit the Parity Signer to authenticate the transfer.</p>
|
||||
</div>);
|
||||
}
|
||||
return (<div>
|
||||
<p>Your transaction has been posted. Please visit the Parity Signer to authenticate the transfer.</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderForm () {
|
||||
const selectedMeta = metaDataKeys[this.state.metaKeyIndex];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SelectField
|
||||
floatingLabelText='Choose the meta-data to add'
|
||||
fullWidth
|
||||
value={ this.state.metaKeyIndex }
|
||||
onChange={ this.onMetaKeyChange }>
|
||||
|
||||
{ this.renderMetaKeyItems() }
|
||||
|
||||
</SelectField>
|
||||
|
||||
<InputText
|
||||
key={ selectedMeta.value }
|
||||
floatingLabelText={ `${selectedMeta.label} value` }
|
||||
hintText={ `The value of the ${selectedMeta.label.toLowerCase()} (${selectedMeta.validation === ADDRESS_TYPE ? 'Address' : 'Url Hint'})` }
|
||||
|
||||
validationType={ selectedMeta.validation }
|
||||
onChange={ this.onChange } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMetaKeyItems () {
|
||||
return metaDataKeys.map((key, index) => (
|
||||
<MenuItem
|
||||
value={ index }
|
||||
key={ index }
|
||||
label={ key.label } primaryText={ key.label } />
|
||||
));
|
||||
}
|
||||
|
||||
onShowDialog = () => {
|
||||
this.setState({ showDialog: true });
|
||||
}
|
||||
|
||||
onClose = () => {
|
||||
this.setState(initState);
|
||||
}
|
||||
|
||||
onAdd = () => {
|
||||
const { index } = this.props;
|
||||
|
||||
const keyIndex = this.state.metaKeyIndex;
|
||||
const key = metaDataKeys[keyIndex].value;
|
||||
|
||||
this.props.handleAddMeta(
|
||||
index,
|
||||
key,
|
||||
this.state.form.value
|
||||
);
|
||||
|
||||
this.setState({ complete: true });
|
||||
}
|
||||
|
||||
onChange = (valid, value) => {
|
||||
this.setState({
|
||||
form: {
|
||||
valid, value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMetaKeyChange = (event, metaKeyIndex) => {
|
||||
this.setState({ metaKeyIndex, form: {
|
||||
...[this.state.form],
|
||||
valid: false,
|
||||
value: ''
|
||||
} });
|
||||
}
|
||||
|
||||
}
|
||||
17
js/src/dapps/tokenreg/Tokens/Token/index.js
Normal file
17
js/src/dapps/tokenreg/Tokens/Token/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './token';
|
||||
140
js/src/dapps/tokenreg/Tokens/Token/token.css
Normal file
140
js/src/dapps/tokenreg/Tokens/Token/token.css
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.token{
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
width: 20rem;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.token-container, .token-content, .token-meta {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.token-content, .token-meta {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.token-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
-webkit-filter: blur(5px);
|
||||
filter: blur(5px);
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.token-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.full-width .token-container {
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.full-width .token-content {
|
||||
width: 20rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.token-content > div, .token-meta > div {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.loading {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.name {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2rem;
|
||||
padding: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
.meta-query {
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.meta-key {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
margin-top: 0.5rem;
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: -0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.meta-image {
|
||||
width: 100%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.meta-image img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.meta-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.unregister {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.add-meta {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pending {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
background-color: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.dialog h3 {
|
||||
color: rgba(50, 100, 150, 1) !important;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
338
js/src/dapps/tokenreg/Tokens/Token/token.js
Normal file
338
js/src/dapps/tokenreg/Tokens/Token/token.js
Normal file
@@ -0,0 +1,338 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import Paper from 'material-ui/Paper';
|
||||
import { RaisedButton, SelectField, MenuItem } from 'material-ui';
|
||||
|
||||
import FindIcon from 'material-ui/svg-icons/action/find-in-page';
|
||||
import DeleteIcon from 'material-ui/svg-icons/action/delete';
|
||||
|
||||
import Loading from '../../Loading';
|
||||
import Chip from '../../Chip';
|
||||
import AddMeta from './add-meta';
|
||||
|
||||
import styles from './token.css';
|
||||
|
||||
import { metaDataKeys } from '../../constants';
|
||||
|
||||
import { api } from '../../parity';
|
||||
|
||||
export default class Token extends Component {
|
||||
static propTypes = {
|
||||
handleMetaLookup: PropTypes.func.isRequired,
|
||||
address: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
owner: PropTypes.string.isRequired,
|
||||
|
||||
handleAddMeta: PropTypes.func,
|
||||
handleUnregister: PropTypes.func,
|
||||
|
||||
tla: PropTypes.string,
|
||||
base: PropTypes.number,
|
||||
totalSupply: PropTypes.number,
|
||||
meta: PropTypes.object,
|
||||
isMetaLoading: PropTypes.bool,
|
||||
ownerAccountInfo: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
meta: PropTypes.object
|
||||
}),
|
||||
metaPending: PropTypes.bool,
|
||||
metaMined: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
isPending: PropTypes.bool,
|
||||
isTokenOwner: PropTypes.bool.isRequired,
|
||||
|
||||
fullWidth: PropTypes.bool
|
||||
};
|
||||
|
||||
state = {
|
||||
metaKeyIndex: 0
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isLoading, fullWidth } = this.props;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={ [ styles.token, styles.loading ].join(' ') }>
|
||||
<Loading size={ 1 } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (fullWidth) {
|
||||
return (<div className={ styles['full-width'] }>
|
||||
{ this.renderContent() }
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<Paper zDepth={ 1 } className={ styles.token } style={ {
|
||||
backgroundColor: 'none'
|
||||
} }>
|
||||
<div className={ styles['token-bg'] } />
|
||||
{ this.renderContent() }
|
||||
</Paper>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
const { address, tla, base, name, meta, owner, totalSupply } = this.props;
|
||||
|
||||
return (<div className={ styles['token-container'] }>
|
||||
{ this.renderIsPending() }
|
||||
|
||||
<div className={ styles['token-content'] }>
|
||||
<div className={ styles.title }>{ tla }</div>
|
||||
<div className={ styles.name }>"{ name }"</div>
|
||||
|
||||
{ this.renderBase(base) }
|
||||
{ this.renderTotalSupply(totalSupply, base, tla) }
|
||||
{ this.renderAddress(address) }
|
||||
{ this.renderOwner(owner) }
|
||||
</div>
|
||||
|
||||
<div className={ styles['token-meta'] }>
|
||||
<div className={ styles['meta-form'] }>
|
||||
<SelectField
|
||||
floatingLabelText='Choose the meta-data to look-up'
|
||||
fullWidth
|
||||
value={ this.state.metaKeyIndex }
|
||||
onChange={ this.onMetaKeyChange }>
|
||||
|
||||
{ this.renderMetaKeyItems() }
|
||||
|
||||
</SelectField>
|
||||
|
||||
<RaisedButton
|
||||
label='Lookup'
|
||||
icon={ <FindIcon /> }
|
||||
primary
|
||||
fullWidth
|
||||
onTouchTap={ this.onMetaLookup } />
|
||||
</div>
|
||||
|
||||
{ this.renderMeta(meta) }
|
||||
{ this.renderAddMeta() }
|
||||
{ this.renderUnregister() }
|
||||
</div>
|
||||
|
||||
{ this.renderMetaPending() }
|
||||
{ this.renderMetaMined() }
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderMetaKeyItems () {
|
||||
return metaDataKeys.map((key, index) => (
|
||||
<MenuItem
|
||||
value={ index }
|
||||
key={ index }
|
||||
label={ key.label } primaryText={ key.label } />
|
||||
));
|
||||
}
|
||||
|
||||
renderBase (base) {
|
||||
if (!base || base < 0) return null;
|
||||
return (
|
||||
<Chip
|
||||
value={ base.toString() }
|
||||
label='Base' />
|
||||
);
|
||||
}
|
||||
|
||||
renderAddress (address) {
|
||||
if (!address) return null;
|
||||
return (
|
||||
<Chip
|
||||
isAddress
|
||||
value={ address }
|
||||
label='Address' />
|
||||
);
|
||||
}
|
||||
|
||||
renderTotalSupply (totalSupply, base, tla) {
|
||||
const balance = Math.round((totalSupply / base) * 100) / 100;
|
||||
|
||||
return (
|
||||
<Chip
|
||||
value={ `${balance.toString()} ${tla}` }
|
||||
label='Total' />
|
||||
);
|
||||
}
|
||||
|
||||
renderOwner (owner) {
|
||||
if (!owner) return null;
|
||||
|
||||
const ownerInfo = this.props.ownerAccountInfo;
|
||||
|
||||
const displayValue = (ownerInfo && ownerInfo.name)
|
||||
? ownerInfo.name
|
||||
: owner;
|
||||
|
||||
return (
|
||||
<Chip
|
||||
isAddress
|
||||
displayValue={ displayValue }
|
||||
value={ owner }
|
||||
label='Owner' />
|
||||
);
|
||||
}
|
||||
|
||||
renderIsPending () {
|
||||
const { isPending } = this.props;
|
||||
|
||||
if (!isPending) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ styles.pending } />
|
||||
);
|
||||
}
|
||||
|
||||
renderAddMeta () {
|
||||
if (!this.props.isTokenOwner) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<AddMeta
|
||||
handleAddMeta={ this.props.handleAddMeta }
|
||||
isTokenOwner={ this.props.isTokenOwner }
|
||||
index={ this.props.index } />
|
||||
);
|
||||
}
|
||||
|
||||
renderUnregister () {
|
||||
if (!this.props.isTokenOwner) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RaisedButton
|
||||
className={ styles.unregister }
|
||||
label='Unregister'
|
||||
icon={ <DeleteIcon /> }
|
||||
secondary
|
||||
fullWidth
|
||||
onTouchTap={ this.onUnregister } />
|
||||
);
|
||||
}
|
||||
|
||||
renderMeta (meta) {
|
||||
const isMetaLoading = this.props.isMetaLoading;
|
||||
|
||||
if (isMetaLoading) {
|
||||
return (<div>
|
||||
<Loading size={ 0.5 } />
|
||||
</div>);
|
||||
}
|
||||
|
||||
if (!meta) return;
|
||||
|
||||
const metaData = metaDataKeys.find(m => m.value === meta.query);
|
||||
|
||||
if (!meta.value) {
|
||||
return (<div>
|
||||
<p className={ styles['meta-query'] }>
|
||||
No <span className={ styles['meta-key'] }>
|
||||
{ metaData.label.toLowerCase() }
|
||||
</span> meta-data...
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
if (meta.query === 'IMG') {
|
||||
const imageHash = meta.value.replace(/^0x/, '');
|
||||
|
||||
return (<div>
|
||||
<p className={ styles['meta-query'] }>
|
||||
<span className={ styles['meta-key'] }>
|
||||
{ metaData.label }
|
||||
</span> meta-data:
|
||||
</p>
|
||||
<div className={ styles['meta-image'] }>
|
||||
<img src={ `http://127.0.0.1:8080/api/content/${imageHash}/` } />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
if (meta.query === 'A') {
|
||||
const address = meta.value.slice(0, 42);
|
||||
|
||||
return (<div>
|
||||
<p className={ styles['meta-query'] }>
|
||||
<span className={ styles['meta-key'] }>
|
||||
{ metaData.label }
|
||||
</span> meta-data:
|
||||
</p>
|
||||
<p className={ styles['meta-value'] }>
|
||||
{ api.util.toChecksumAddress(address) }
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<p className={ styles['meta-query'] }>
|
||||
<span className={ styles['meta-key'] }>
|
||||
{ metaData.label }
|
||||
</span> meta-data:
|
||||
</p>
|
||||
<p className={ styles['meta-value'] }>{ meta.value }</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderMetaPending () {
|
||||
const isMetaPending = this.props.metaPending;
|
||||
if (!isMetaPending) return;
|
||||
|
||||
return (<div>
|
||||
<p className={ styles['meta-info'] }>
|
||||
Meta-Data pending...
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
renderMetaMined () {
|
||||
const isMetaMined = this.props.metaMined;
|
||||
if (!isMetaMined) return;
|
||||
|
||||
return (<div>
|
||||
<p className={ styles['meta-info'] }>
|
||||
Meta-Data saved on the blockchain!
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
onUnregister = () => {
|
||||
const index = this.props.index;
|
||||
this.props.handleUnregister(index);
|
||||
}
|
||||
|
||||
onMetaLookup = () => {
|
||||
const keyIndex = this.state.metaKeyIndex;
|
||||
const key = metaDataKeys[keyIndex].value;
|
||||
const index = this.props.index;
|
||||
|
||||
this.props.handleMetaLookup(index, key);
|
||||
}
|
||||
|
||||
onMetaKeyChange = (event, metaKeyIndex) => {
|
||||
this.setState({ metaKeyIndex });
|
||||
}
|
||||
}
|
||||
262
js/src/dapps/tokenreg/Tokens/actions.js
Normal file
262
js/src/dapps/tokenreg/Tokens/actions.js
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { getTokenTotalSupply } from '../utils';
|
||||
|
||||
const { bytesToHex } = window.parity.api.util;
|
||||
|
||||
export const SET_TOKENS_LOADING = 'SET_TOKENS_LOADING';
|
||||
export const setTokensLoading = (isLoading) => ({
|
||||
type: SET_TOKENS_LOADING,
|
||||
isLoading
|
||||
});
|
||||
|
||||
export const SET_TOKEN_COUNT = 'SET_TOKEN_COUNT';
|
||||
export const setTokenCount = (tokenCount) => ({
|
||||
type: SET_TOKEN_COUNT,
|
||||
tokenCount
|
||||
});
|
||||
|
||||
export const SET_TOKEN_DATA = 'SET_TOKEN_DATA';
|
||||
export const setTokenData = (index, tokenData) => ({
|
||||
type: SET_TOKEN_DATA,
|
||||
index, tokenData
|
||||
});
|
||||
|
||||
export const SET_TOKEN_META = 'SET_TOKEN_META';
|
||||
export const setTokenMeta = (index, meta) => ({
|
||||
type: SET_TOKEN_META,
|
||||
index, meta
|
||||
});
|
||||
|
||||
export const SET_TOKEN_LOADING = 'SET_TOKEN_LOADING';
|
||||
export const setTokenLoading = (index, isLoading) => ({
|
||||
type: SET_TOKEN_LOADING,
|
||||
index, isLoading
|
||||
});
|
||||
|
||||
export const SET_TOKEN_META_LOADING = 'SET_TOKEN_META_LOADING';
|
||||
export const setTokenMetaLoading = (index, isMetaLoading) => ({
|
||||
type: SET_TOKEN_META_LOADING,
|
||||
index, isMetaLoading
|
||||
});
|
||||
|
||||
export const SET_TOKEN_PENDING = 'SET_TOKEN_PENDING';
|
||||
export const setTokenPending = (index, isPending) => ({
|
||||
type: SET_TOKEN_PENDING,
|
||||
index, isPending
|
||||
});
|
||||
|
||||
export const DELETE_TOKEN = 'DELETE_TOKEN';
|
||||
export const deleteToken = (index) => ({
|
||||
type: DELETE_TOKEN,
|
||||
index
|
||||
});
|
||||
|
||||
export const loadTokens = () => (dispatch, getState) => {
|
||||
console.log('loading tokens...');
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
dispatch(setTokensLoading(true));
|
||||
|
||||
contractInstance
|
||||
.tokenCount
|
||||
.call()
|
||||
.then((count) => {
|
||||
const tokenCount = parseInt(count);
|
||||
console.log(`token count: ${tokenCount}`);
|
||||
dispatch(setTokenCount(tokenCount));
|
||||
|
||||
for (let i = 0; i < tokenCount; i++) {
|
||||
dispatch(loadToken(i));
|
||||
}
|
||||
|
||||
dispatch(setTokensLoading(false));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('loadTokens error', e);
|
||||
});
|
||||
};
|
||||
|
||||
export const loadToken = (index) => (dispatch, getState) => {
|
||||
console.log('loading token', index);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
const userAccounts = state.accounts.list;
|
||||
const accountsInfo = state.accounts.accountsInfo;
|
||||
|
||||
dispatch(setTokenLoading(index, true));
|
||||
|
||||
contractInstance
|
||||
.token
|
||||
.call({}, [ parseInt(index) ])
|
||||
.then((result) => {
|
||||
const tokenOwner = result[4];
|
||||
|
||||
const isTokenOwner = userAccounts
|
||||
.filter(a => a.address === tokenOwner)
|
||||
.length > 0;
|
||||
|
||||
const data = {
|
||||
index: parseInt(index),
|
||||
address: result[0],
|
||||
tla: result[1],
|
||||
base: result[2].toNumber(),
|
||||
name: result[3],
|
||||
owner: tokenOwner,
|
||||
ownerAccountInfo: accountsInfo[tokenOwner],
|
||||
isPending: false,
|
||||
isTokenOwner
|
||||
};
|
||||
|
||||
return data;
|
||||
})
|
||||
.then(data => {
|
||||
return getTokenTotalSupply(data.address)
|
||||
.then(totalSupply => {
|
||||
data.totalSupply = totalSupply;
|
||||
return data;
|
||||
});
|
||||
})
|
||||
.then(data => {
|
||||
// If no total supply, must not be a proper token
|
||||
if (data.totalSupply === null) {
|
||||
dispatch(setTokenData(index, null));
|
||||
dispatch(setTokenLoading(index, false));
|
||||
return;
|
||||
}
|
||||
|
||||
data.totalSupply = data.totalSupply.toNumber();
|
||||
console.log(`token loaded: #${index}`, data);
|
||||
dispatch(setTokenData(index, data));
|
||||
dispatch(setTokenLoading(index, false));
|
||||
})
|
||||
.catch((e) => {
|
||||
dispatch(setTokenData(index, null));
|
||||
dispatch(setTokenLoading(index, false));
|
||||
|
||||
if (!e instanceof TypeError) {
|
||||
console.error(`loadToken #${index} error`, e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const queryTokenMeta = (index, query) => (dispatch, getState) => {
|
||||
console.log('loading token meta', index, query);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
const startDate = Date.now();
|
||||
dispatch(setTokenMetaLoading(index, true));
|
||||
|
||||
contractInstance
|
||||
.meta
|
||||
.call({}, [ index, query ])
|
||||
.then((value) => {
|
||||
const meta = {
|
||||
query,
|
||||
value: value.find(v => v !== 0) ? bytesToHex(value) : null
|
||||
};
|
||||
|
||||
console.log(`token meta loaded: #${index}`, value);
|
||||
dispatch(setTokenMeta(index, meta));
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch(setTokenMetaLoading(index, false));
|
||||
}, 500 - (Date.now() - startDate));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(`loadToken #${index} error`, e);
|
||||
});
|
||||
};
|
||||
|
||||
export const addTokenMeta = (index, key, value) => (dispatch, getState) => {
|
||||
console.log('add token meta', index, key, value);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
const token = state.tokens.tokens.find(t => t.index === index);
|
||||
|
||||
const options = { from: token.owner };
|
||||
const values = [ index, key, value ];
|
||||
|
||||
contractInstance
|
||||
.setMeta
|
||||
.estimateGas(options, values)
|
||||
.then((gasEstimate) => {
|
||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||
console.log(`addTokenMeta: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
|
||||
|
||||
return contractInstance.setMeta.postTransaction(options, values);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(`addTokenMeta: #${index} error`, e);
|
||||
});
|
||||
};
|
||||
|
||||
export const addGithubhintURL = (from, key, url) => (dispatch, getState) => {
|
||||
console.log('add githubhint url', key, url);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.githubhint.instance;
|
||||
|
||||
const options = { from };
|
||||
|
||||
const values = [ key, url ];
|
||||
|
||||
contractInstance
|
||||
.hintURL
|
||||
.estimateGas(options, values)
|
||||
.then((gasEstimate) => {
|
||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||
console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
|
||||
|
||||
return contractInstance.hintURL.postTransaction(options, values);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('addGithubhintURL error', e);
|
||||
});
|
||||
};
|
||||
|
||||
export const unregisterToken = (index) => (dispatch, getState) => {
|
||||
console.log('unregistering token', index);
|
||||
|
||||
const state = getState();
|
||||
const contractInstance = state.status.contract.instance;
|
||||
|
||||
const values = [ index ];
|
||||
const options = {
|
||||
from: state.accounts.selected.address
|
||||
};
|
||||
|
||||
contractInstance
|
||||
.unregister
|
||||
.estimateGas(options, values)
|
||||
.then((gasEstimate) => {
|
||||
options.gas = gasEstimate.mul(1.2).toFixed(0);
|
||||
console.log(`transfer: gas estimated as ${gasEstimate.toFixed(0)} setting to ${options.gas}`);
|
||||
|
||||
return contractInstance.unregister.postTransaction(options, values);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(`unregisterToken #${index} error`, e);
|
||||
});
|
||||
};
|
||||
80
js/src/dapps/tokenreg/Tokens/container.js
Normal file
80
js/src/dapps/tokenreg/Tokens/container.js
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Tokens from './tokens';
|
||||
|
||||
import { loadTokens, queryTokenMeta, unregisterToken, addTokenMeta } from './actions';
|
||||
|
||||
class TokensContainer extends Component {
|
||||
static propTypes = {
|
||||
isOwner: PropTypes.bool,
|
||||
isLoading: PropTypes.bool,
|
||||
tokens: PropTypes.array,
|
||||
tokenCount: PropTypes.number,
|
||||
onLoadTokens: PropTypes.func,
|
||||
accounts: PropTypes.array
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
this.props.onLoadTokens();
|
||||
}
|
||||
|
||||
render () {
|
||||
console.log(this.props);
|
||||
return (
|
||||
<Tokens
|
||||
{ ...this.props }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const { list } = state.accounts;
|
||||
const { isLoading, tokens, tokenCount } = state.tokens;
|
||||
|
||||
const { isOwner } = state.status.contract;
|
||||
|
||||
return { isLoading, tokens, tokenCount, isOwner, accounts: list };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
onLoadTokens: () => {
|
||||
dispatch(loadTokens());
|
||||
},
|
||||
|
||||
handleMetaLookup: (index, query) => {
|
||||
dispatch(queryTokenMeta(index, query));
|
||||
},
|
||||
|
||||
handleUnregister: (index) => {
|
||||
dispatch(unregisterToken(index));
|
||||
},
|
||||
|
||||
handleAddMeta: (index, key, value) => {
|
||||
dispatch(addTokenMeta(index, key, value));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TokensContainer);
|
||||
17
js/src/dapps/tokenreg/Tokens/index.js
Normal file
17
js/src/dapps/tokenreg/Tokens/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './container';
|
||||
114
js/src/dapps/tokenreg/Tokens/reducer.js
Normal file
114
js/src/dapps/tokenreg/Tokens/reducer.js
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {
|
||||
SET_TOKENS_LOADING,
|
||||
SET_TOKEN_COUNT,
|
||||
SET_TOKEN_DATA,
|
||||
SET_TOKEN_META,
|
||||
SET_TOKEN_LOADING,
|
||||
SET_TOKEN_META_LOADING,
|
||||
SET_TOKEN_PENDING,
|
||||
DELETE_TOKEN
|
||||
} from './actions';
|
||||
|
||||
const initialState = {
|
||||
isLoading: true,
|
||||
tokens: [],
|
||||
tokenCount: 0
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case SET_TOKENS_LOADING:
|
||||
return { ...state, isLoading: action.isLoading };
|
||||
|
||||
case SET_TOKEN_COUNT:
|
||||
return { ...state, tokenCount: action.tokenCount };
|
||||
|
||||
case SET_TOKEN_DATA: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
tokens[index] = {
|
||||
...tokens[index],
|
||||
...action.tokenData
|
||||
};
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
case SET_TOKEN_META: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
tokens[index] = {
|
||||
...tokens[index],
|
||||
meta: action.meta
|
||||
};
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
case SET_TOKEN_LOADING: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
tokens[index] = {
|
||||
...tokens[index],
|
||||
isLoading: action.isLoading
|
||||
};
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
case SET_TOKEN_META_LOADING: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
tokens[index] = {
|
||||
...tokens[index],
|
||||
isMetaLoading: action.isMetaLoading
|
||||
};
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
case SET_TOKEN_PENDING: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
tokens[index] = {
|
||||
...tokens[index],
|
||||
isPending: action.isPending
|
||||
};
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
case DELETE_TOKEN: {
|
||||
const index = action.index;
|
||||
const tokens = [].concat(state.tokens);
|
||||
|
||||
delete tokens[index];
|
||||
|
||||
return { ...state, tokens: tokens };
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
24
js/src/dapps/tokenreg/Tokens/tokens.css
Normal file
24
js/src/dapps/tokenreg/Tokens/tokens.css
Normal file
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.tokens {
|
||||
width: 90%;
|
||||
padding-top: 2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
}
|
||||
68
js/src/dapps/tokenreg/Tokens/tokens.js
Normal file
68
js/src/dapps/tokenreg/Tokens/tokens.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import Token from './Token';
|
||||
import Loading from '../Loading';
|
||||
|
||||
import styles from './tokens.css';
|
||||
|
||||
export default class Tokens extends Component {
|
||||
static propTypes = {
|
||||
handleAddMeta: PropTypes.func.isRequired,
|
||||
handleUnregister: PropTypes.func.isRequired,
|
||||
handleMetaLookup: PropTypes.func.isRequired,
|
||||
isOwner: PropTypes.bool.isRequired,
|
||||
isLoading: PropTypes.bool.isRequired,
|
||||
tokens: PropTypes.array,
|
||||
accounts: PropTypes.array
|
||||
};
|
||||
|
||||
render () {
|
||||
const { isLoading, tokens } = this.props;
|
||||
const loading = isLoading ? (<Loading size={ 2 } />) : null;
|
||||
|
||||
return (
|
||||
<div className={ styles.tokens }>
|
||||
{ this.renderTokens(tokens) }
|
||||
{ loading }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderTokens (tokens) {
|
||||
const { accounts } = this.props;
|
||||
|
||||
return tokens.map((token, index) => {
|
||||
if (!token || !token.tla) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isTokenOwner = !!accounts.find((account) => account.address === token.owner);
|
||||
|
||||
return (
|
||||
<Token
|
||||
{ ...token }
|
||||
handleUnregister={ this.props.handleUnregister }
|
||||
handleMetaLookup={ this.props.handleMetaLookup }
|
||||
handleAddMeta={ this.props.handleAddMeta }
|
||||
key={ index }
|
||||
isTokenOwner={ isTokenOwner } />
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
30
js/src/dapps/tokenreg/constants.js
Normal file
30
js/src/dapps/tokenreg/constants.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { HEX_TYPE, ADDRESS_TYPE } from './Inputs/validation';
|
||||
|
||||
export const metaDataKeys = [
|
||||
{
|
||||
label: 'Image',
|
||||
value: 'IMG',
|
||||
validation: HEX_TYPE
|
||||
},
|
||||
{
|
||||
label: 'Address',
|
||||
value: 'A',
|
||||
validation: ADDRESS_TYPE
|
||||
}
|
||||
];
|
||||
21
js/src/dapps/tokenreg/parity.js
Normal file
21
js/src/dapps/tokenreg/parity.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const { api } = window.parity;
|
||||
|
||||
export {
|
||||
api
|
||||
};
|
||||
28
js/src/dapps/tokenreg/reducers.js
Normal file
28
js/src/dapps/tokenreg/reducers.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { combineReducers } from 'redux';
|
||||
|
||||
import status from './Status/reducer';
|
||||
import tokens from './Tokens/reducer';
|
||||
import actions from './Actions/reducer';
|
||||
import accounts from './Accounts/reducer';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
status, tokens, actions, accounts
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
22
js/src/dapps/tokenreg/store.js
Normal file
22
js/src/dapps/tokenreg/store.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import reducer from './reducers';
|
||||
|
||||
export default createStore(reducer, applyMiddleware(thunk));
|
||||
37
js/src/dapps/tokenreg/utils.js
Normal file
37
js/src/dapps/tokenreg/utils.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { api } from './parity';
|
||||
|
||||
import { eip20 as eip20Abi } from '../../contracts/abi';
|
||||
|
||||
export const getTokenTotalSupply = (tokenAddress) => {
|
||||
return api
|
||||
.eth
|
||||
.getCode(tokenAddress)
|
||||
.then(code => {
|
||||
if (!code || /^(0x)?0?$/.test(code)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const contract = api.newContract(eip20Abi, tokenAddress);
|
||||
|
||||
return contract
|
||||
.instance
|
||||
.totalSupply
|
||||
.call({}, []);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user